aienvmp 0.1.52 → 0.1.54
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 +20 -0
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/commands/context.js +2 -0
- package/src/commands/doctor.js +4 -0
- package/src/commands/status.js +1 -0
- package/src/commands/summary.js +9 -0
- package/src/contract.js +2 -2
- package/src/preflight.js +82 -0
- package/src/render.js +2 -0
package/BUGFIXES.md
CHANGED
|
@@ -106,6 +106,18 @@ Short record of bugs, fixes, and follow-up checks.
|
|
|
106
106
|
- Fix: `agentFiles` now records path, existence, pointer marker state, role, and install command; recommended actions suggest installing a pointer without failing local work.
|
|
107
107
|
- Verification: tests cover sync pointer scanning, recommended action output, and dashboard status labels.
|
|
108
108
|
|
|
109
|
+
### AI consumers had to inspect the full manifest for pointer state
|
|
110
|
+
|
|
111
|
+
- Issue: `status`, `context`, and `doctor` did not expose a compact pointer summary even after manifest scanning detected it.
|
|
112
|
+
- Fix: `agentPointers` now appears in status/preflight, context JSON, doctor JSON, and summary markdown.
|
|
113
|
+
- Verification: regression tests cover status, context, doctor, schema, and summary outputs.
|
|
114
|
+
|
|
115
|
+
### AI continuation readiness was spread across several fields
|
|
116
|
+
|
|
117
|
+
- Issue: AI consumers had to infer readiness from status, intents, activity, follow-ups, pointer state, and SBOM risk separately.
|
|
118
|
+
- Fix: `aiReadiness` now provides one advisory ready/review signal across status, context, doctor, summary, and dashboard.
|
|
119
|
+
- Verification: regression tests cover ready/review summaries, text status output, schema metadata, and dashboard rendering.
|
|
120
|
+
|
|
109
121
|
## Template
|
|
110
122
|
|
|
111
123
|
### Title
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.54
|
|
4
|
+
|
|
5
|
+
- Added `aiReadiness` to the shared preflight/status contract.
|
|
6
|
+
- Added root `aiReadiness` to `context --json`.
|
|
7
|
+
- Added `aiReadiness` to `doctor --json` as advisory metadata.
|
|
8
|
+
- Printed `ai-readiness` in plain `aienvmp status` output.
|
|
9
|
+
- Added `AI readiness` to `.aienvmp/summary.md`.
|
|
10
|
+
- Added an AI readiness item to the dashboard audit band.
|
|
11
|
+
- Updated README, schema metadata, and regression tests for the ready/review signal.
|
|
12
|
+
|
|
13
|
+
## 0.1.53
|
|
14
|
+
|
|
15
|
+
- Added `agentPointers` to the shared AI preflight/status contract.
|
|
16
|
+
- Added `agentPointers` to `context --json` at the root for quick AI access.
|
|
17
|
+
- Added `agentPointers` to `doctor --json` without making missing pointers a blocking warning.
|
|
18
|
+
- Added agent pointer status to `.aienvmp/summary.md`.
|
|
19
|
+
- Added `agentPointers` to the stable schema contract metadata.
|
|
20
|
+
- Preserved legacy boolean `agentFiles` compatibility in preflight summaries.
|
|
21
|
+
- Added regression tests for status, context, doctor, schema, and summary pointer outputs.
|
|
22
|
+
|
|
3
23
|
## 0.1.52
|
|
4
24
|
|
|
5
25
|
- Expanded `manifest.agentFiles` from booleans to lightweight agent instruction metadata.
|
package/README.md
CHANGED
|
@@ -50,6 +50,7 @@ AIENV.md # Markdown env map for AI agents
|
|
|
50
50
|
- `schema --json` prints the stable AI-readable output contract without scanning.
|
|
51
51
|
- `summary.md` is the short CI/AI handoff view.
|
|
52
52
|
- `status.json.nextAgent` tells the next AI what to read and whether to review first.
|
|
53
|
+
- `aiReadiness` gives a one-field ready/review signal for AI continuation.
|
|
53
54
|
- `dependencyReadSet` lists manifests and lockfiles before package or security changes.
|
|
54
55
|
- `sbomRisk` gives AI a compact light-SBOM risk level, signals, and next command.
|
|
55
56
|
- `coordination.conflictTargets` shows where multiple agents are planning changes.
|
|
@@ -73,6 +74,7 @@ npx aienvmp snippet gemini
|
|
|
73
74
|
|
|
74
75
|
Snippets point each AI to `status`, `summary.md`, `context --json`, intent, and checkpoint without taking over the instruction file.
|
|
75
76
|
`sync` records whether those pointers are installed, and `doctor` can recommend installing one without blocking local work.
|
|
77
|
+
`status`, `context --json`, and `doctor --json` expose the same `agentPointers` summary for AI consumers.
|
|
76
78
|
|
|
77
79
|
## Commands
|
|
78
80
|
|
package/package.json
CHANGED
package/src/commands/context.js
CHANGED
|
@@ -26,7 +26,9 @@ export async function contextWorkspace(args) {
|
|
|
26
26
|
console.log(JSON.stringify({
|
|
27
27
|
status: warnings.length ? "review-required" : "clear",
|
|
28
28
|
preflight,
|
|
29
|
+
aiReadiness: preflight.aiReadiness,
|
|
29
30
|
coordination: preflight.coordination,
|
|
31
|
+
agentPointers: preflight.agentPointers,
|
|
30
32
|
sbomRisk: preflight.sbomRisk,
|
|
31
33
|
followUps: preflight.followUps,
|
|
32
34
|
decision,
|
package/src/commands/doctor.js
CHANGED
|
@@ -5,6 +5,7 @@ import { intentsPath, manifestPath, timelinePath, workspaceDir } from "../paths.
|
|
|
5
5
|
import { loadPolicy, policyWarnings } from "../policy.js";
|
|
6
6
|
import { recommendedActions } from "../actions.js";
|
|
7
7
|
import { enforcementAdvice, strictResult } from "../enforcement.js";
|
|
8
|
+
import { buildPreflight } from "../preflight.js";
|
|
8
9
|
|
|
9
10
|
export { strictResult } from "../enforcement.js";
|
|
10
11
|
|
|
@@ -17,6 +18,7 @@ export async function doctorWorkspace(args) {
|
|
|
17
18
|
const intents = openIntents(await readJsonl(intentsPath(dir)));
|
|
18
19
|
const warnings = [...diagnose(manifest, { timeline, intents }), ...policyWarnings(manifest, policy)];
|
|
19
20
|
const actions = recommendedActions(manifest, { warnings, intents });
|
|
21
|
+
const preflight = buildPreflight(manifest, warnings, intents, timeline);
|
|
20
22
|
const strict = strictResult(warnings, args);
|
|
21
23
|
const exitBehavior = {
|
|
22
24
|
mode: strict.enabled ? "strict" : "advisory",
|
|
@@ -32,6 +34,8 @@ export async function doctorWorkspace(args) {
|
|
|
32
34
|
exitBehavior,
|
|
33
35
|
trust: manifest.trust || {},
|
|
34
36
|
policy,
|
|
37
|
+
aiReadiness: preflight.aiReadiness,
|
|
38
|
+
agentPointers: preflight.agentPointers,
|
|
35
39
|
openIntentCount: intents.length,
|
|
36
40
|
warnings,
|
|
37
41
|
recommendedActions: actions,
|
package/src/commands/status.js
CHANGED
|
@@ -22,6 +22,7 @@ export async function statusWorkspace(args) {
|
|
|
22
22
|
console.log(JSON.stringify(output, null, 2));
|
|
23
23
|
} else if (!args.quiet) {
|
|
24
24
|
console.log(`${output.state}: ${output.summary}`);
|
|
25
|
+
console.log(`ai-readiness: ${output.aiReadiness?.level || "unknown"} - ${output.aiReadiness?.next || "Run aienvmp context --json for details."}`);
|
|
25
26
|
console.log(`next: ${output.nextCommand}`);
|
|
26
27
|
console.log(`ai: ${output.quickstart.readFirst} -> ${output.quickstart.detailCommand}`);
|
|
27
28
|
console.log(`intent: ${output.intentTargets[0]?.command || output.commands.recordIntent}`);
|
package/src/commands/summary.js
CHANGED
|
@@ -51,6 +51,8 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
51
51
|
const dependencyProtocol = status.dependencyChangeProtocol || {};
|
|
52
52
|
const dependencyCommands = dependencyProtocol.commands || {};
|
|
53
53
|
const dependencyFiles = dependencyFilesFor(status.dependencyReadSet);
|
|
54
|
+
const agentPointers = status.agentPointers || {};
|
|
55
|
+
const aiReadiness = status.aiReadiness || {};
|
|
54
56
|
|
|
55
57
|
return [
|
|
56
58
|
"# aienvmp summary",
|
|
@@ -61,6 +63,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
61
63
|
`- runtimes: ${valueOrZero(counts.runtimes)} / dependencies: ${valueOrZero(counts.dependencies)} / vulnerabilities: ${valueOrZero(counts.vulnerabilities)}`,
|
|
62
64
|
`- light SBOM risk: ${riskLevel} (${riskScore}) / scanner: ${scanner}`,
|
|
63
65
|
`- next: ${next}`,
|
|
66
|
+
`- AI readiness: ${aiReadiness.level || "unknown"} / ${aiReadiness.next || "Run aienvmp context --json for details."}`,
|
|
64
67
|
`- AI read first: ${readFirst}, then ${detail}`,
|
|
65
68
|
`- mode: advisory by default; strict is opt-in with ${strict}`,
|
|
66
69
|
"",
|
|
@@ -86,6 +89,12 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
86
89
|
`- after: ${dependencyCommands.checkpointAfterChange || "aienvmp checkpoint --actor agent:id --summary dependency-change --target dependency"}`,
|
|
87
90
|
`- package manager policy: ${dependencyProtocol.packageManagerPolicy || "not-detected"}`,
|
|
88
91
|
"",
|
|
92
|
+
"## Agent pointers",
|
|
93
|
+
"",
|
|
94
|
+
`- installed: ${toList(agentPointers.installed).join(", ") || "none"}`,
|
|
95
|
+
`- missing: ${toList(agentPointers.missing).join(", ") || "none"}`,
|
|
96
|
+
`- next: ${agentPointers.next || "Run aienvmp snippet codex --write if AI agents need instruction-file discovery."}`,
|
|
97
|
+
"",
|
|
89
98
|
"## Artifacts",
|
|
90
99
|
"",
|
|
91
100
|
"- AIENV.md",
|
package/src/contract.js
CHANGED
|
@@ -4,7 +4,7 @@ export function preflightContract() {
|
|
|
4
4
|
version: 1,
|
|
5
5
|
stability: "additive",
|
|
6
6
|
requiredFields: ["schemaVersion", "state", "decision", "quickstart", "commands", "artifacts"],
|
|
7
|
-
aiEntryFields: ["state", "summary", "nextAgent", "coordination", "agentActivity", "sbomRisk", "followUps", "dependencyReadSet", "dependencyChangeProtocol"],
|
|
7
|
+
aiEntryFields: ["state", "summary", "aiReadiness", "nextAgent", "coordination", "agentActivity", "agentPointers", "sbomRisk", "followUps", "dependencyReadSet", "dependencyChangeProtocol"],
|
|
8
8
|
rule: "Consumers should ignore unknown fields and treat missing optional fields as unavailable."
|
|
9
9
|
};
|
|
10
10
|
}
|
|
@@ -28,7 +28,7 @@ export function schemaContract() {
|
|
|
28
28
|
},
|
|
29
29
|
context: {
|
|
30
30
|
command: "aienvmp context --json",
|
|
31
|
-
rootFields: ["status", "preflight", "coordination", "decision", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
31
|
+
rootFields: ["status", "preflight", "aiReadiness", "coordination", "agentPointers", "decision", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
32
32
|
},
|
|
33
33
|
handoff: {
|
|
34
34
|
command: "aienvmp handoff --json",
|
package/src/preflight.js
CHANGED
|
@@ -17,6 +17,8 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
17
17
|
const followUps = pendingFollowUps(timeline);
|
|
18
18
|
const agentActivity = agentActivitySummary(timeline);
|
|
19
19
|
const sbomRisk = manifest.lightSbom?.riskSummary || {};
|
|
20
|
+
const agentPointers = agentPointerSummary(manifest.agentFiles);
|
|
21
|
+
const aiReadiness = aiReadinessSummary({ state, decision, coordination, agentActivity, agentPointers, sbomRisk, followUps });
|
|
20
22
|
return {
|
|
21
23
|
schemaVersion: 1,
|
|
22
24
|
contract: preflightContract(),
|
|
@@ -58,6 +60,8 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
58
60
|
nextAgent: nextAgentHint(state, dependencyReadSet, dependencyChangeProtocol),
|
|
59
61
|
coordination,
|
|
60
62
|
agentActivity,
|
|
63
|
+
agentPointers,
|
|
64
|
+
aiReadiness,
|
|
61
65
|
sbomRisk,
|
|
62
66
|
followUps,
|
|
63
67
|
intentTargets,
|
|
@@ -87,6 +91,31 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
87
91
|
};
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
function aiReadinessSummary({ state, decision, coordination, agentActivity, agentPointers, sbomRisk, followUps }) {
|
|
95
|
+
const blockers = [];
|
|
96
|
+
const review = [];
|
|
97
|
+
if (state !== "clear") review.push("status review required");
|
|
98
|
+
if ((coordination?.conflictTargets || []).length) review.push("open intent conflicts");
|
|
99
|
+
if ((agentActivity?.multiActorTargets || []).length) review.push("multi-agent environment activity");
|
|
100
|
+
if ((followUps || []).length) review.push("pending environment follow-ups");
|
|
101
|
+
if (["urgent", "high"].includes(sbomRisk?.level)) review.push("high light SBOM risk");
|
|
102
|
+
if ((agentPointers?.targets || []).length && (agentPointers?.installedCount || 0) === 0) review.push("no agent instruction pointer installed");
|
|
103
|
+
|
|
104
|
+
const level = review.length ? "review" : "ready";
|
|
105
|
+
const next = level === "ready"
|
|
106
|
+
? "AI agents can continue project-local work; record intent before environment changes."
|
|
107
|
+
: "Review listed signals before another AI changes runtimes, dependencies, package managers, Docker, or global tools.";
|
|
108
|
+
return {
|
|
109
|
+
level,
|
|
110
|
+
projectLocalWork: decision?.canContinueProjectLocalWork ? "allowed" : "review-first",
|
|
111
|
+
environmentChanges: decision?.canChangeEnvironmentWithoutReview ? "allowed" : "intent-and-review-first",
|
|
112
|
+
signals: review,
|
|
113
|
+
blockers,
|
|
114
|
+
next,
|
|
115
|
+
mode: "advisory"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
90
119
|
function agentActivitySummary(timeline = []) {
|
|
91
120
|
const lastHandoffAt = lastTime(timeline, (item) => item.type === "agent-handoff");
|
|
92
121
|
const envRecords = timeline
|
|
@@ -123,6 +152,59 @@ function agentActivitySummary(timeline = []) {
|
|
|
123
152
|
};
|
|
124
153
|
}
|
|
125
154
|
|
|
155
|
+
export function agentPointerSummary(agentFiles = {}) {
|
|
156
|
+
const entries = Object.entries(agentFiles || {}).filter(([name]) => ["agents", "claude", "gemini"].includes(name));
|
|
157
|
+
const targets = entries.map(([name, item]) => {
|
|
158
|
+
const normalized = normalizeAgentFile(item);
|
|
159
|
+
return {
|
|
160
|
+
name,
|
|
161
|
+
role: normalized.role || (name === "agents" ? "codex" : name),
|
|
162
|
+
file: normalized.path || defaultAgentFile(name),
|
|
163
|
+
exists: normalized.exists,
|
|
164
|
+
hasPointer: normalized.hasAienvmpPointer,
|
|
165
|
+
installCommand: normalized.installCommand || defaultInstallCommand(name)
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
const installed = targets.filter((item) => item.hasPointer);
|
|
169
|
+
const missing = targets.filter((item) => !item.hasPointer);
|
|
170
|
+
return {
|
|
171
|
+
installedCount: installed.length,
|
|
172
|
+
missingCount: missing.length,
|
|
173
|
+
installed: installed.map((item) => item.role),
|
|
174
|
+
missing: missing.map((item) => item.role),
|
|
175
|
+
targets,
|
|
176
|
+
next: missing.length
|
|
177
|
+
? `Install a pointer with ${missing[0].installCommand} if this workspace uses that AI.`
|
|
178
|
+
: "Agent instruction pointers are installed for detected AI instruction files.",
|
|
179
|
+
mode: "advisory"
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function normalizeAgentFile(item) {
|
|
184
|
+
if (typeof item === "boolean") {
|
|
185
|
+
return { exists: item, hasAienvmpPointer: item };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
path: item?.path || "",
|
|
189
|
+
exists: item?.exists === true,
|
|
190
|
+
hasAienvmpPointer: item?.hasAienvmpPointer === true,
|
|
191
|
+
installCommand: item?.installCommand || "",
|
|
192
|
+
role: item?.role || ""
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function defaultAgentFile(name) {
|
|
197
|
+
if (name === "claude") return "CLAUDE.md";
|
|
198
|
+
if (name === "gemini") return "GEMINI.md";
|
|
199
|
+
return "AGENTS.md";
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function defaultInstallCommand(name) {
|
|
203
|
+
if (name === "claude") return "aienvmp snippet claude --write";
|
|
204
|
+
if (name === "gemini") return "aienvmp snippet gemini --write";
|
|
205
|
+
return "aienvmp snippet codex --write";
|
|
206
|
+
}
|
|
207
|
+
|
|
126
208
|
function coordinationSummary(intents = []) {
|
|
127
209
|
const byTarget = new Map();
|
|
128
210
|
for (const intent of intents) {
|
package/src/render.js
CHANGED
|
@@ -493,6 +493,7 @@ const nextAction=reviewRequired?'Review before environment changes':'Proceed wit
|
|
|
493
493
|
const auditItem=(key,value,hint,klass='')=>\`<div class="audit-item \${klass}"><div class="audit-k">\${key}</div><div class="audit-v">\${value}</div><div class="audit-hint">\${hint}</div></div>\`;
|
|
494
494
|
const driftLabel=warnings.length?'detected':'none';
|
|
495
495
|
const nextAgent=manifest.preflight?.nextAgent||{};
|
|
496
|
+
const aiReadiness=manifest.preflight?.aiReadiness||{};
|
|
496
497
|
const coordination=manifest.preflight?.coordination||{};
|
|
497
498
|
const conflictTargets=coordination.conflictTargets||[];
|
|
498
499
|
const handoffFiles=nextAgent.dependencyFiles?.length?nextAgent.dependencyFiles:(dependencyReadSet[0]?[dependencyReadSet[0].manifest,...(dependencyReadSet[0].lockfiles||[])].filter(Boolean):[]);
|
|
@@ -509,6 +510,7 @@ document.getElementById('app').innerHTML=\`
|
|
|
509
510
|
</header>
|
|
510
511
|
<section class="audit" aria-label="Audit summary">
|
|
511
512
|
\${auditItem('AI decision',reviewRequired?'review required':'can proceed',nextAction,reviewRequired?'review':'primary')}
|
|
513
|
+
\${auditItem('AI readiness',aiReadiness.level||'unknown',aiReadiness.next||'Run aienvmp context --json for details.',aiReadiness.level==='ready'?'primary':'review')}
|
|
512
514
|
\${auditItem('Runtime drift',driftLabel,warnings.length?'Policy, runtime, or coordination warning detected':'No drift warnings detected',warnings.length?'review':'')}
|
|
513
515
|
\${auditItem('Open env changes',String(intents.length),intents.length?'Resolve or coordinate before changes':'No pending env changes')}
|
|
514
516
|
\${auditItem('Trust',trustState,trustState==='verified'?'Human or CI verified':'Machine observed; not AI-verified')}
|