aienvmp 0.1.37 → 0.1.38
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 +8 -0
- package/README.md +6 -0
- package/package.json +1 -1
- package/src/commands/compile.js +5 -1
- package/src/commands/status.js +2 -0
- package/src/preflight.js +85 -1
- package/src/render.js +36 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.38
|
|
4
|
+
|
|
5
|
+
- Added a 10-second AI quickstart flow to the shared preflight contract and status output.
|
|
6
|
+
- Added preflight intent target recommendations so agents can record runtime, package manager, dependency, Docker, or coordination changes consistently.
|
|
7
|
+
- Surfaced AI intent target recommendations in the dashboard so humans can review the same target guidance.
|
|
8
|
+
- Added the same quickstart and intent target guidance to `AIENV.md` so Markdown-first agents receive the current preflight.
|
|
9
|
+
- Aligned AGENTS/Claude/Gemini pointer snippets with the same status-first, target-aware AI flow.
|
|
10
|
+
|
|
3
11
|
## 0.1.37
|
|
4
12
|
|
|
5
13
|
- Added `lightSbom` to the manifest as an AI-ready package and vulnerability summary.
|
package/README.md
CHANGED
|
@@ -22,6 +22,8 @@ npx aienvmp plan
|
|
|
22
22
|
npx aienvmp handoff
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
10-second AI flow: `aienvmp status --write` -> `aienvmp context --json` -> intent before environment changes.
|
|
26
|
+
|
|
25
27
|
Optional deeper read-only checks:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
@@ -53,9 +55,13 @@ AIENV.md
|
|
|
53
55
|
.aienvmp/dashboard.html # includes dependencies, plan, remediation, and environment cards
|
|
54
56
|
```
|
|
55
57
|
|
|
58
|
+
`AIENV.md` includes the 10-second AI flow and recommended intent targets for Markdown-first agents.
|
|
59
|
+
|
|
56
60
|
Trust states are machine-readable: `observed`, `planned`, `changed`, `review`, `verified`, `stale`.
|
|
57
61
|
`status.json` also lists AI read order, artifact paths, and safe commands.
|
|
58
62
|
`status`, `context`, `plan`, and `handoff` share the same AI preflight contract.
|
|
63
|
+
Preflight also recommends the intent target, so agents do not guess between runtime, package manager, dependency, Docker, or coordination changes.
|
|
64
|
+
The dashboard shows the same intent target guidance for human review.
|
|
59
65
|
|
|
60
66
|
AI agents can observe, plan, and record. Only a human or CI should mark environment facts as verified.
|
|
61
67
|
|
package/package.json
CHANGED
package/src/commands/compile.js
CHANGED
|
@@ -5,6 +5,7 @@ import { openIntents, readJsonl, readTimeline } from "../timeline.js";
|
|
|
5
5
|
import { aiEnvPath, intentsPath, manifestPath, timelinePath, workspaceDir } from "../paths.js";
|
|
6
6
|
import { renderAIEnv } from "../render.js";
|
|
7
7
|
import { loadPolicy, policyWarnings } from "../policy.js";
|
|
8
|
+
import { buildPreflight } from "../preflight.js";
|
|
8
9
|
|
|
9
10
|
export async function compileWorkspace(args) {
|
|
10
11
|
const dir = workspaceDir(args);
|
|
@@ -14,7 +15,10 @@ export async function compileWorkspace(args) {
|
|
|
14
15
|
const intents = openIntents(await readJsonl(intentsPath(dir)));
|
|
15
16
|
const policy = await loadPolicy(dir);
|
|
16
17
|
const warnings = [...diagnose(manifest, { timeline, intents }), ...policyWarnings(manifest, policy)];
|
|
17
|
-
const rendered = renderAIEnv(
|
|
18
|
+
const rendered = renderAIEnv({
|
|
19
|
+
...manifest,
|
|
20
|
+
preflight: buildPreflight(manifest, warnings, intents)
|
|
21
|
+
}, timeline, warnings, intents, policy);
|
|
18
22
|
await fs.writeFile(aiEnvPath(dir), rendered, "utf8");
|
|
19
23
|
if (!args.quiet) {
|
|
20
24
|
console.log(`compiled ${aiEnvPath(dir)}`);
|
package/src/commands/status.js
CHANGED
|
@@ -23,6 +23,8 @@ export async function statusWorkspace(args) {
|
|
|
23
23
|
} else if (!args.quiet) {
|
|
24
24
|
console.log(`${output.state}: ${output.summary}`);
|
|
25
25
|
console.log(`next: ${output.nextCommand}`);
|
|
26
|
+
console.log(`ai: ${output.quickstart.readFirst} -> ${output.quickstart.detailCommand}`);
|
|
27
|
+
console.log(`intent: ${output.intentTargets[0]?.command || output.commands.recordIntent}`);
|
|
26
28
|
console.log(`strict: ${output.enforcement.recommendedCommand}`);
|
|
27
29
|
if (artifact) console.log(`status: ${artifact}`);
|
|
28
30
|
}
|
package/src/preflight.js
CHANGED
|
@@ -8,6 +8,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
|
|
|
8
8
|
const actions = recommendedActions(manifest, { warnings, intents });
|
|
9
9
|
const state = decision.reviewRequired ? "review-required" : "clear";
|
|
10
10
|
const topAction = actions[0] || null;
|
|
11
|
+
const intentTargets = recommendedIntentTargets(manifest, warnings, intents);
|
|
11
12
|
return {
|
|
12
13
|
schemaVersion: 1,
|
|
13
14
|
state,
|
|
@@ -43,6 +44,8 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
|
|
|
43
44
|
projectLocalWork: decision.canContinueProjectLocalWork ? "allowed" : "review-first",
|
|
44
45
|
environmentChanges: decision.canChangeEnvironmentWithoutReview ? "allowed" : "intent-and-review-first"
|
|
45
46
|
},
|
|
47
|
+
quickstart: agentQuickstart(decision.reviewRequired),
|
|
48
|
+
intentTargets,
|
|
46
49
|
artifacts: preflightArtifacts(),
|
|
47
50
|
readOrder: [
|
|
48
51
|
".aienvmp/status.json",
|
|
@@ -58,13 +61,94 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
|
|
|
58
61
|
context: "aienvmp context --json",
|
|
59
62
|
plan: "aienvmp plan --write",
|
|
60
63
|
handoff: "aienvmp handoff --record --actor agent:id",
|
|
61
|
-
recordIntent: "aienvmp intent --actor agent:id --action planned-change"
|
|
64
|
+
recordIntent: intentTargets[0]?.command || "aienvmp intent --actor agent:id --action planned-change"
|
|
62
65
|
},
|
|
63
66
|
topAction,
|
|
64
67
|
nextCommand: topAction?.command || decision.nextCommand
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
function recommendedIntentTargets(manifest = {}, warnings = [], intents = []) {
|
|
72
|
+
const targets = [];
|
|
73
|
+
for (const warning of warnings) {
|
|
74
|
+
addTarget(targets, targetFromWarning(warning), warning.message || warning.code, warning.code);
|
|
75
|
+
}
|
|
76
|
+
for (const intent of intents) {
|
|
77
|
+
addTarget(targets, intent.target || targetFromText(intent.action), `Open intent from ${intent.actor || "unknown"}.`, "open-intent");
|
|
78
|
+
}
|
|
79
|
+
const pmPolicy = manifest.lightSbom?.packageManagerPolicy;
|
|
80
|
+
if (pmPolicy?.status === "review-required") {
|
|
81
|
+
addTarget(targets, "package-manager", pmPolicy.guidance, "package-manager-policy");
|
|
82
|
+
}
|
|
83
|
+
if (Number(manifest.security?.summary?.total || 0) > 0) {
|
|
84
|
+
addTarget(targets, "dependency", "Security findings are dependency-related; record dependency intent before remediation.", "security");
|
|
85
|
+
}
|
|
86
|
+
if (Number(manifest.dependencySnapshot?.summary?.packages || 0) > 0) {
|
|
87
|
+
addTarget(targets, "dependency", "Dependency manifests detected; use this target before package changes.", "dependency-snapshot");
|
|
88
|
+
}
|
|
89
|
+
if (!targets.length) {
|
|
90
|
+
addTarget(targets, "environment", "Default target when the change affects runtime, dependency, container, or global tool state.", "default");
|
|
91
|
+
}
|
|
92
|
+
return targets.slice(0, 5).map((item) => ({
|
|
93
|
+
...item,
|
|
94
|
+
command: `aienvmp intent --actor agent:id --action planned-change --target ${item.target}`
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function addTarget(targets, target, reason, source) {
|
|
99
|
+
const normalized = normalizeTarget(target);
|
|
100
|
+
if (!normalized) return;
|
|
101
|
+
const existing = targets.find((item) => item.target === normalized);
|
|
102
|
+
if (existing) {
|
|
103
|
+
if (source && !existing.sources.includes(source)) existing.sources.push(source);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
targets.push({ target: normalized, reason: reason || "Environment change target.", sources: source ? [source] : [] });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function targetFromWarning(warning = {}) {
|
|
110
|
+
if (warning.target) return warning.target;
|
|
111
|
+
const code = warning.code || "";
|
|
112
|
+
if (code.includes("node")) return "node";
|
|
113
|
+
if (code.includes("python")) return "python";
|
|
114
|
+
if (code.includes("docker")) return "docker";
|
|
115
|
+
if (code.includes("lockfile") || code.includes("package-manager")) return "package-manager";
|
|
116
|
+
if (code.includes("security")) return "dependency";
|
|
117
|
+
if (code.includes("intent") || code.includes("handoff")) return "coordination";
|
|
118
|
+
return targetFromText(`${warning.message || ""} ${code}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function targetFromText(text = "") {
|
|
122
|
+
const normalized = String(text).toLowerCase();
|
|
123
|
+
for (const target of ["node", "python", "docker", "package-manager", "dependency", "npm", "pnpm", "yarn", "uv", "pip", "pipx"]) {
|
|
124
|
+
if (normalized.includes(target)) return target;
|
|
125
|
+
}
|
|
126
|
+
if (normalized.includes("package manager") || normalized.includes("lockfile")) return "package-manager";
|
|
127
|
+
if (normalized.includes("vulnerab") || normalized.includes("package")) return "dependency";
|
|
128
|
+
return "";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function normalizeTarget(target = "") {
|
|
132
|
+
const normalized = String(target).trim().toLowerCase();
|
|
133
|
+
if (["npm", "pnpm", "yarn"].includes(normalized)) return "package-manager";
|
|
134
|
+
if (["pip", "pipx", "uv"].includes(normalized)) return "python";
|
|
135
|
+
return normalized;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function agentQuickstart(reviewRequired) {
|
|
139
|
+
return {
|
|
140
|
+
label: "10-second AI flow",
|
|
141
|
+
readFirst: "aienvmp status --write",
|
|
142
|
+
detailCommand: "aienvmp context --json",
|
|
143
|
+
beforeEnvironmentChange: "aienvmp intent --actor agent:id --action planned-change --target <runtime|package-manager|docker|dependency>",
|
|
144
|
+
afterEnvironmentChange: "aienvmp sync && aienvmp record --actor agent:id --summary what-changed",
|
|
145
|
+
handoff: "aienvmp handoff --record --actor agent:id",
|
|
146
|
+
rule: reviewRequired
|
|
147
|
+
? "Review warnings or open intents before environment changes; project-local work may continue."
|
|
148
|
+
: "Continue project-local work; record intent before environment changes."
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
68
152
|
export function preflightArtifacts() {
|
|
69
153
|
return {
|
|
70
154
|
status: ".aienvmp/status.json",
|
package/src/render.js
CHANGED
|
@@ -16,6 +16,7 @@ export function renderAIEnv(manifest, timeline = [], warnings = [], intents = []
|
|
|
16
16
|
lines.push("5. After environment changes, run `aienvmp sync`.");
|
|
17
17
|
lines.push("6. Record what changed with `aienvmp record --actor agent:id --summary what-changed`.");
|
|
18
18
|
lines.push("7. At handoff, run `aienvmp handoff --record --actor agent:id`.", "");
|
|
19
|
+
lines.push(...preflightLines(manifest.preflight), "");
|
|
19
20
|
lines.push("## Current Policy", "");
|
|
20
21
|
lines.push(...policyLines(policy));
|
|
21
22
|
lines.push("- Enforcement: non-blocking by default; warnings require review but do not lock the machine.");
|
|
@@ -69,6 +70,31 @@ export function renderAIEnv(manifest, timeline = [], warnings = [], intents = []
|
|
|
69
70
|
return lines.join("\n");
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
function preflightLines(preflight = {}) {
|
|
74
|
+
const quickstart = preflight.quickstart;
|
|
75
|
+
const targets = preflight.intentTargets || [];
|
|
76
|
+
const lines = ["## 10-Second AI Flow", ""];
|
|
77
|
+
if (quickstart) {
|
|
78
|
+
lines.push(`- Read first: \`${quickstart.readFirst}\``);
|
|
79
|
+
lines.push(`- Detail: \`${quickstart.detailCommand}\``);
|
|
80
|
+
lines.push(`- Before env change: \`${quickstart.beforeEnvironmentChange}\``);
|
|
81
|
+
lines.push(`- After env change: \`${quickstart.afterEnvironmentChange}\``);
|
|
82
|
+
lines.push(`- Handoff: \`${quickstart.handoff}\``);
|
|
83
|
+
lines.push(`- Rule: ${quickstart.rule}`);
|
|
84
|
+
} else {
|
|
85
|
+
lines.push("- Run `aienvmp status --write`, then `aienvmp context --json` before environment changes.");
|
|
86
|
+
}
|
|
87
|
+
lines.push("", "## Recommended Intent Targets", "");
|
|
88
|
+
if (targets.length) {
|
|
89
|
+
for (const target of targets.slice(0, 5)) {
|
|
90
|
+
lines.push(`- ${target.target}: \`${target.command}\` - ${target.reason}`);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
lines.push("- environment: `aienvmp intent --actor agent:id --action planned-change --target environment`");
|
|
94
|
+
}
|
|
95
|
+
return lines;
|
|
96
|
+
}
|
|
97
|
+
|
|
72
98
|
export function renderAgentPointer(target = "agents") {
|
|
73
99
|
const label = target === "claude" ? "Claude" : target === "gemini" ? "Gemini" : "AI agents";
|
|
74
100
|
return `## aienvmp Environment Map
|
|
@@ -77,12 +103,12 @@ ${label} should use \`aienvmp\` as the workspace environment source of truth.
|
|
|
77
103
|
|
|
78
104
|
Before changing runtimes, package managers, Docker settings, global packages, or environment policy:
|
|
79
105
|
|
|
80
|
-
1. Run \`aienvmp
|
|
81
|
-
2.
|
|
82
|
-
3.
|
|
83
|
-
4.
|
|
84
|
-
5.
|
|
85
|
-
6.
|
|
106
|
+
1. Run \`aienvmp status --write\`.
|
|
107
|
+
2. Run \`aienvmp context --json\` for details.
|
|
108
|
+
3. Read \`AIENV.md\`.
|
|
109
|
+
4. If status or context says \`review-required\`, ask the user before changing the environment.
|
|
110
|
+
5. Record planned environment changes with the recommended target, for example \`aienvmp intent --actor agent:id --action planned-change --target dependency\`.
|
|
111
|
+
6. After environment changes, run \`aienvmp sync\` and \`aienvmp record --actor agent:id --summary what-changed\`.
|
|
86
112
|
7. At handoff, run \`aienvmp handoff --record --actor agent:id\`.
|
|
87
113
|
|
|
88
114
|
\`aienvmp\` does not replace this instruction file. It provides the live env map, lightweight runtime SBOM, intent log, timeline, and dashboard.`;
|
|
@@ -326,6 +352,8 @@ const ciReadinessHtml=ciReadiness.length?'<table>'+ciReadiness.map(s=>\`<tr><th>
|
|
|
326
352
|
const enforcementProfile=manifest.preflight?.enforcementProfile||{};
|
|
327
353
|
const strictCommands=enforcementProfile.strictCommands||[];
|
|
328
354
|
const enforcementHtml=\`<table><tr><th>Default</th><td><code>\${esc(enforcementProfile.defaultMode||'advisory')}</code></td></tr><tr><th>Local</th><td>\${esc(enforcementProfile.localOperation||'non-blocking')}</td></tr><tr><th>Strict</th><td>\${esc(enforcementProfile.strictUse||'CI or explicit checks only')}</td></tr><tr><th>Recommended</th><td><code>\${esc(enforcementProfile.recommendedStrictCommand||'aienvmp doctor --strict all')}</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(enforcementProfile.reason||'Warnings stay advisory unless strict mode is requested.')}</div>\`;
|
|
355
|
+
const intentTargets=manifest.preflight?.intentTargets||[];
|
|
356
|
+
const intentTargetsHtml=intentTargets.length?'<div class="timeline">'+intentTargets.slice(0,5).map(t=>\`<div class="event"><time>\${esc(t.target)}</time><div><b>\${esc(t.target)}</b> \${esc(t.reason||'Record this target before environment changes.')}\${t.command?\`<div class="path">\${esc(t.command)}</div>\`:''}</div></div>\`).join('')+'</div>':'<div class="okline">No specific target recommendation. Use <code>aienvmp intent --actor agent:id --action planned-change</code>.</div>';
|
|
329
357
|
const card=(title,badge,body)=>\`<section class="card"><div class="card-head"><h2>\${title}</h2>\${badge||''}</div>\${body}</section>\`;
|
|
330
358
|
const reviewRequired=warnings.length>0||intents.length>0;
|
|
331
359
|
const recentChanges=timeline.slice(-8).length;
|
|
@@ -369,6 +397,8 @@ document.getElementById('app').innerHTML=\`
|
|
|
369
397
|
<aside>
|
|
370
398
|
\${card('Recommended Actions','<span class="pill">'+actions.length+' actions</span>',actionsHtml)}
|
|
371
399
|
<div style="height:14px"></div>
|
|
400
|
+
\${card('AI Intent Targets','<span class="pill">'+intentTargets.length+' targets</span>',intentTargetsHtml)}
|
|
401
|
+
<div style="height:14px"></div>
|
|
372
402
|
\${card('AI Plan Artifacts',plan.markdown||plan.json?'<span class="pill">written</span>':'<span class="pill off">not written</span>',planHtml)}
|
|
373
403
|
<div style="height:14px"></div>
|
|
374
404
|
\${card('Remediation Steps',remediation.length?'<span class="pill warn">'+remediation.length+' items</span>':'<span class="pill off">none</span>',remediationHtml)}
|