aienvmp 0.1.50 → 0.1.52
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/.agents/skills/aienvmp/SKILL.md +19 -13
- package/BUGFIXES.md +12 -0
- package/CHANGELOG.md +20 -0
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/actions.js +20 -0
- package/src/cli.js +1 -1
- package/src/commands/summary.js +22 -0
- package/src/manifest.js +22 -1
- package/src/preflight.js +2 -0
- package/src/render.js +24 -8
|
@@ -11,20 +11,26 @@ The goal is to help multiple AI agents avoid silently installing or using differ
|
|
|
11
11
|
|
|
12
12
|
## Preflight
|
|
13
13
|
|
|
14
|
-
Before environment-impacting work, run:
|
|
14
|
+
Before environment-impacting work, run the light preflight first:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npx aienvmp
|
|
17
|
+
npx aienvmp status --write
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Then read the short handoff:
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
```bash
|
|
23
|
+
cat .aienvmp/summary.md
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For deeper machine-readable context, use:
|
|
23
27
|
|
|
24
28
|
```bash
|
|
25
29
|
npx aienvmp context --json
|
|
26
30
|
```
|
|
27
31
|
|
|
32
|
+
If the output says `review-required`, do not change global runtimes, package managers, Docker settings, dependencies, lockfiles, or global packages without asking the user.
|
|
33
|
+
|
|
28
34
|
## Before Environment Changes
|
|
29
35
|
|
|
30
36
|
Record intent before changing shared environment state:
|
|
@@ -38,26 +44,25 @@ Use this for changes such as:
|
|
|
38
44
|
- installing or upgrading Node, Python, Docker, package managers, or global CLIs
|
|
39
45
|
- changing `.nvmrc`, `.python-version`, `mise.toml`, `.tool-versions`, or `.aienvmp/policy.yml`
|
|
40
46
|
- switching package managers
|
|
47
|
+
- changing dependencies or lockfiles
|
|
41
48
|
- changing Docker daemon/context assumptions
|
|
42
49
|
|
|
43
50
|
## After Environment Changes
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
Use the one-command checkpoint after an accepted environment change:
|
|
46
53
|
|
|
47
54
|
```bash
|
|
48
|
-
npx aienvmp
|
|
55
|
+
npx aienvmp checkpoint --actor agent:codex --summary "<what changed>" --target "<tool-or-runtime>"
|
|
49
56
|
```
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
This records the change, refreshes the env map, writes status/summary/SBOM artifacts, and records a handoff.
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
npx aienvmp record --actor agent:codex --summary "<what changed>" --target "<tool-or-runtime>" --evidence "<command or file>"
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Resolve the original intent if complete:
|
|
60
|
+
If checkpoint is not available, use the explicit fallback:
|
|
58
61
|
|
|
59
62
|
```bash
|
|
60
|
-
npx aienvmp
|
|
63
|
+
npx aienvmp sync
|
|
64
|
+
npx aienvmp record --actor agent:codex --summary "<what changed>" --target "<tool-or-runtime>" --evidence "<command or file>"
|
|
65
|
+
npx aienvmp handoff --record --actor agent:codex
|
|
61
66
|
```
|
|
62
67
|
|
|
63
68
|
## Safety Rules
|
|
@@ -66,6 +71,7 @@ npx aienvmp resolve --actor agent:codex --id "<intent-id>"
|
|
|
66
71
|
- Treat policy mismatches as review-required.
|
|
67
72
|
- Do not install, upgrade, downgrade, or remove global software unless the user explicitly asks.
|
|
68
73
|
- Prefer project-local version files and local environments.
|
|
74
|
+
- Do not switch package managers or rewrite lockfiles only to satisfy a tool preference.
|
|
69
75
|
- Do not use warnings as permission to interrupt production or shared workspace operations.
|
|
70
76
|
- Use `npx aienvmp doctor --ci` only in CI or explicit strict-mode automation.
|
|
71
77
|
|
package/BUGFIXES.md
CHANGED
|
@@ -94,6 +94,18 @@ Short record of bugs, fixes, and follow-up checks.
|
|
|
94
94
|
- Fix: `readJson` now strips a leading UTF-8 BOM before parsing.
|
|
95
95
|
- Verification: regression tests cover BOM JSON parsing and Windows smoke testing confirmed dependency counts in `summary.md`.
|
|
96
96
|
|
|
97
|
+
### Agent instructions lagged behind the current protocol
|
|
98
|
+
|
|
99
|
+
- Issue: packaged skill and pointer snippets still emphasized older context/record flows and did not direct agents to `summary.md`.
|
|
100
|
+
- Fix: snippets and the Codex skill now use the current status, summary, context, intent, and checkpoint flow with agent-specific actor examples.
|
|
101
|
+
- Verification: regression tests cover snippet output for AGENTS.md, Claude, and Gemini, and summary/status tests cover the read order and dependency protocol.
|
|
102
|
+
|
|
103
|
+
### AI pointer files were only detected as booleans
|
|
104
|
+
|
|
105
|
+
- Issue: AI and humans could see that an instruction file existed, but not whether it actually contained the aienvmp pointer.
|
|
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
|
+
- Verification: tests cover sync pointer scanning, recommended action output, and dashboard status labels.
|
|
108
|
+
|
|
97
109
|
## Template
|
|
98
110
|
|
|
99
111
|
### Title
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.52
|
|
4
|
+
|
|
5
|
+
- Expanded `manifest.agentFiles` from booleans to lightweight agent instruction metadata.
|
|
6
|
+
- Detected whether AGENTS.md, CLAUDE.md, and GEMINI.md contain the aienvmp pointer marker.
|
|
7
|
+
- Added install commands and roles to agent instruction metadata.
|
|
8
|
+
- Added a low-priority recommended action when no AI instruction pointer is installed.
|
|
9
|
+
- Updated the dashboard Agent Pointers card to distinguish installed pointers, missing pointers, and missing files.
|
|
10
|
+
- Updated README guidance to mention pointer detection and non-blocking doctor recommendations.
|
|
11
|
+
- Added regression tests for pointer scanning, pointer recommendations, dashboard rendering, and sync output.
|
|
12
|
+
|
|
13
|
+
## 0.1.51
|
|
14
|
+
|
|
15
|
+
- Updated Codex/Claude/Gemini pointer snippets to use the current `status -> summary.md -> context` read order.
|
|
16
|
+
- Added agent-specific actor examples for Codex, Claude, and Gemini snippet output.
|
|
17
|
+
- Added dependency and lockfile changes to the snippet environment-change scope.
|
|
18
|
+
- Updated the packaged Codex skill to prefer `status --write`, `summary.md`, and `checkpoint`.
|
|
19
|
+
- Added `.aienvmp/summary.md` to the shared preflight read order and next-agent hint.
|
|
20
|
+
- Added a Dependency changes section to `summary.md` with read files, intent command, checkpoint command, and package-manager policy.
|
|
21
|
+
- Updated README agent-file guidance and added regression coverage for the AI snippet and summary protocol.
|
|
22
|
+
|
|
3
23
|
## 0.1.50
|
|
4
24
|
|
|
5
25
|
- Added `aienvmp summary` for a compact Markdown AI/CI handoff view.
|
package/README.md
CHANGED
|
@@ -65,11 +65,15 @@ AIENV.md # Markdown env map for AI agents
|
|
|
65
65
|
`aienvmp` does not replace AGENTS.md, CLAUDE.md, or GEMINI.md. It gives them a live environment source of truth.
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
+
npx aienvmp snippet codex
|
|
68
69
|
npx aienvmp snippet agents
|
|
69
70
|
npx aienvmp snippet claude
|
|
70
71
|
npx aienvmp snippet gemini
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
Snippets point each AI to `status`, `summary.md`, `context --json`, intent, and checkpoint without taking over the instruction file.
|
|
75
|
+
`sync` records whether those pointers are installed, and `doctor` can recommend installing one without blocking local work.
|
|
76
|
+
|
|
73
77
|
## Commands
|
|
74
78
|
|
|
75
79
|
```bash
|
package/package.json
CHANGED
package/src/actions.js
CHANGED
|
@@ -21,6 +21,7 @@ export function recommendedActions(manifest = {}, context = {}) {
|
|
|
21
21
|
|
|
22
22
|
actions.push(...securityActions(manifest.security));
|
|
23
23
|
actions.push(...sbomRiskActions(manifest.lightSbom?.riskSummary));
|
|
24
|
+
actions.push(...agentPointerActions(manifest.agentFiles));
|
|
24
25
|
|
|
25
26
|
if (hasRuntimePolicyWarning(warnings)) {
|
|
26
27
|
actions.push(action("review-version-policy", "medium", "runtime", "Detected runtime or package manager policy drift. Prefer project-local version files and ask before global changes."));
|
|
@@ -74,6 +75,25 @@ function securityActions(security = {}) {
|
|
|
74
75
|
)];
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
function agentPointerActions(agentFiles = {}) {
|
|
79
|
+
const known = Object.entries(agentFiles || {}).filter(([name]) => ["agents", "claude", "gemini"].includes(name));
|
|
80
|
+
if (!known.length) return [];
|
|
81
|
+
if (known.some(([, item]) => hasPointer(item))) return [];
|
|
82
|
+
const first = known.find(([, item]) => item?.installCommand) || known[0];
|
|
83
|
+
return [action(
|
|
84
|
+
"install-agent-pointer",
|
|
85
|
+
"low",
|
|
86
|
+
"agent-instructions",
|
|
87
|
+
"Install an aienvmp pointer in an agent instruction file so future AI agents discover the env map before changing runtimes or dependencies.",
|
|
88
|
+
first?.[1]?.installCommand || "aienvmp snippet codex --write"
|
|
89
|
+
)];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function hasPointer(item) {
|
|
93
|
+
if (typeof item === "boolean") return item;
|
|
94
|
+
return item?.hasAienvmpPointer === true;
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
function action(id, priority, category, summary, command = "") {
|
|
78
98
|
return { id, priority, category, summary, command };
|
|
79
99
|
}
|
package/src/cli.js
CHANGED
|
@@ -140,7 +140,7 @@ Advanced:
|
|
|
140
140
|
aienvmp resolve [--dir .] --actor human:you --id <intent-id> [--status resolved|cancelled]
|
|
141
141
|
aienvmp record [--dir .] --actor agent:codex --summary "updated .nvmrc" [--target node] [--before 20] [--after 24]
|
|
142
142
|
aienvmp checkpoint [--dir .] --actor agent:codex --summary "updated dependency" [--target dependency]
|
|
143
|
-
aienvmp snippet [agents|claude|gemini] [--write AGENTS.md]
|
|
143
|
+
aienvmp snippet [agents|codex|claude|gemini] [--write AGENTS.md]
|
|
144
144
|
aienvmp compile [--dir .]
|
|
145
145
|
aienvmp diff [--dir .]
|
|
146
146
|
aienvmp doctor [--dir .] [--json] [--ci] [--strict security|policy|coordination|all]
|
package/src/commands/summary.js
CHANGED
|
@@ -48,6 +48,9 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
48
48
|
const riskSignals = toList(sbomRisk.signals).slice(0, 3);
|
|
49
49
|
const conflictTargets = toList(coordination.conflictTargets);
|
|
50
50
|
const multiActorTargets = toList(activity.multiActorTargets);
|
|
51
|
+
const dependencyProtocol = status.dependencyChangeProtocol || {};
|
|
52
|
+
const dependencyCommands = dependencyProtocol.commands || {};
|
|
53
|
+
const dependencyFiles = dependencyFilesFor(status.dependencyReadSet);
|
|
51
54
|
|
|
52
55
|
return [
|
|
53
56
|
"# aienvmp summary",
|
|
@@ -76,6 +79,13 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
76
79
|
`- signals: ${riskSignals.length ? riskSignals.join("; ") : "none"}`,
|
|
77
80
|
`- verify: ${sbomRisk.next || "Use a dedicated scanner for security decisions."}`,
|
|
78
81
|
"",
|
|
82
|
+
"## Dependency changes",
|
|
83
|
+
"",
|
|
84
|
+
`- read files: ${dependencyFiles.length ? dependencyFiles.join(", ") : "none detected"}`,
|
|
85
|
+
`- before: ${dependencyCommands.recordIntent || "aienvmp intent --actor agent:id --action planned-change --target dependency"}`,
|
|
86
|
+
`- after: ${dependencyCommands.checkpointAfterChange || "aienvmp checkpoint --actor agent:id --summary dependency-change --target dependency"}`,
|
|
87
|
+
`- package manager policy: ${dependencyProtocol.packageManagerPolicy || "not-detected"}`,
|
|
88
|
+
"",
|
|
79
89
|
"## Artifacts",
|
|
80
90
|
"",
|
|
81
91
|
"- AIENV.md",
|
|
@@ -94,3 +104,15 @@ function valueOrZero(value) {
|
|
|
94
104
|
function toList(value) {
|
|
95
105
|
return Array.isArray(value) ? value.filter(Boolean) : [];
|
|
96
106
|
}
|
|
107
|
+
|
|
108
|
+
function dependencyFilesFor(readSet = []) {
|
|
109
|
+
const files = [];
|
|
110
|
+
for (const item of toList(readSet).slice(0, 3)) {
|
|
111
|
+
if (item.manifest) files.push(item.manifest);
|
|
112
|
+
for (const lockfile of toList(item.lockfiles).slice(0, 3)) {
|
|
113
|
+
const file = typeof lockfile === "string" ? lockfile : lockfile?.file;
|
|
114
|
+
if (file && !files.includes(file)) files.push(file);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return files.slice(0, 8);
|
|
118
|
+
}
|
package/src/manifest.js
CHANGED
|
@@ -205,11 +205,32 @@ async function scanAgentFiles(dir) {
|
|
|
205
205
|
};
|
|
206
206
|
const out = {};
|
|
207
207
|
for (const [name, rel] of Object.entries(files)) {
|
|
208
|
-
|
|
208
|
+
const full = path.join(dir, rel);
|
|
209
|
+
const fileExists = await exists(full);
|
|
210
|
+
const content = fileExists ? await fs.readFile(full, "utf8") : "";
|
|
211
|
+
out[name] = {
|
|
212
|
+
path: rel,
|
|
213
|
+
exists: fileExists,
|
|
214
|
+
hasAienvmpPointer: content.includes("<!-- aienvmp:begin -->") && content.includes("<!-- aienvmp:end -->"),
|
|
215
|
+
installCommand: snippetCommand(name),
|
|
216
|
+
role: agentRole(name)
|
|
217
|
+
};
|
|
209
218
|
}
|
|
210
219
|
return out;
|
|
211
220
|
}
|
|
212
221
|
|
|
222
|
+
function snippetCommand(name) {
|
|
223
|
+
if (name === "agents") return "aienvmp snippet codex --write";
|
|
224
|
+
if (["claude", "gemini"].includes(name)) return `aienvmp snippet ${name} --write`;
|
|
225
|
+
return "";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function agentRole(name) {
|
|
229
|
+
if (name === "agents") return "codex";
|
|
230
|
+
if (["claude", "gemini"].includes(name)) return name;
|
|
231
|
+
return "external";
|
|
232
|
+
}
|
|
233
|
+
|
|
213
234
|
function compact(obj) {
|
|
214
235
|
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value));
|
|
215
236
|
}
|
package/src/preflight.js
CHANGED
|
@@ -66,6 +66,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
66
66
|
artifacts: preflightArtifacts(),
|
|
67
67
|
readOrder: [
|
|
68
68
|
".aienvmp/status.json",
|
|
69
|
+
".aienvmp/summary.md",
|
|
69
70
|
"AIENV.md",
|
|
70
71
|
".aienvmp/manifest.json",
|
|
71
72
|
".aienvmp/plan.json",
|
|
@@ -195,6 +196,7 @@ function nextAgentHint(state, dependencyReadSet = [], dependencyChangeProtocol =
|
|
|
195
196
|
return {
|
|
196
197
|
handoffCommand: dependencyChangeProtocol.commands?.handoff || "aienvmp handoff --record --actor agent:id",
|
|
197
198
|
readFirst: ".aienvmp/status.json",
|
|
199
|
+
readSummary: ".aienvmp/summary.md",
|
|
198
200
|
readNext: "aienvmp context --json",
|
|
199
201
|
reviewState: state,
|
|
200
202
|
dependencyFiles,
|
package/src/render.js
CHANGED
|
@@ -114,18 +114,30 @@ function preflightLines(preflight = {}) {
|
|
|
114
114
|
|
|
115
115
|
export function renderAgentPointer(target = "agents") {
|
|
116
116
|
const label = target === "claude" ? "Claude" : target === "gemini" ? "Gemini" : "AI agents";
|
|
117
|
+
const actor = target === "claude"
|
|
118
|
+
? "agent:claude"
|
|
119
|
+
: target === "gemini"
|
|
120
|
+
? "agent:gemini"
|
|
121
|
+
: target === "codex"
|
|
122
|
+
? "agent:codex"
|
|
123
|
+
: "agent:id";
|
|
117
124
|
return `## aienvmp Environment Map
|
|
118
125
|
|
|
119
126
|
${label} should use \`aienvmp\` as the workspace environment source of truth.
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
Fast read order:
|
|
122
129
|
|
|
123
130
|
1. Run \`aienvmp status --write\`.
|
|
124
|
-
2.
|
|
125
|
-
3.
|
|
126
|
-
4.
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
2. Read \`.aienvmp/summary.md\` for the short handoff.
|
|
132
|
+
3. Run \`aienvmp context --json\` for details.
|
|
133
|
+
4. Read \`AIENV.md\` when Markdown context is easier.
|
|
134
|
+
|
|
135
|
+
Before changing runtimes, package managers, Docker settings, global packages, dependencies, lockfiles, or environment policy:
|
|
136
|
+
|
|
137
|
+
1. If status or context says \`review-required\`, ask the user before changing the environment.
|
|
138
|
+
2. Record planned environment changes with the recommended target, for example \`aienvmp intent --actor ${actor} --action planned-change --target dependency\`.
|
|
139
|
+
3. Prefer project-local version files and local environments.
|
|
140
|
+
4. After accepted environment changes, run \`aienvmp checkpoint --actor ${actor} --summary what-changed --target environment\`.
|
|
129
141
|
|
|
130
142
|
\`aienvmp\` does not replace this instruction file. It provides the live env map, lightweight runtime SBOM, intent log, timeline, and dashboard.`;
|
|
131
143
|
}
|
|
@@ -433,7 +445,11 @@ const securityHtml=sec.enabled?\`<table><tr><th>Total</th><td><code>\${esc(secSu
|
|
|
433
445
|
const change=c=>c.type==='changed'?\`\${c.scope} \${c.key}: \${c.before} -> \${c.after}\`:\`\${c.scope} \${c.key}: \${c.type} \${c.after||c.before}\`;
|
|
434
446
|
const timelineLabel=t=>t.change?change(t.change):(t.summary||t.action||t.type||'recorded change');
|
|
435
447
|
const agentNames={agents:'Codex',claude:'Claude',gemini:'Gemini'};
|
|
436
|
-
const
|
|
448
|
+
const agentInfo=v=>typeof v==='object'&&v? v : {exists:!!v,hasAienvmpPointer:!!v,path:''};
|
|
449
|
+
const agentHasPointer=v=>agentInfo(v).hasAienvmpPointer===true;
|
|
450
|
+
const agentStatus=v=>agentHasPointer(v)?'aienvmp pointer installed':(agentInfo(v).exists?'file detected, pointer missing':'not detected');
|
|
451
|
+
const agentCards=Object.entries(agentNames).map(([key,label])=>\`<div class="agent"><strong>\${label}</strong><span>\${esc(agentStatus(manifest.agentFiles?.[key]))}</span>\${agentInfo(manifest.agentFiles?.[key]).installCommand?\`<span class="path">\${esc(agentInfo(manifest.agentFiles?.[key]).installCommand)}</span>\`:''}</div>\`).join('');
|
|
452
|
+
const agentPointerCount=entries(manifest.agentFiles).filter(([,v])=>agentHasPointer(v)).length;
|
|
437
453
|
const warnHtml=warnings.length?'<div class="warnings">'+warnings.map(w=>\`<div class="warning">\${esc(w.message)}</div>\`).join('')+'</div>':'<div class="okline">No blocking environment warnings detected.</div>';
|
|
438
454
|
const timelineHtml=timeline.length?'<div class="timeline">'+timeline.slice(-8).reverse().map(t=>\`<div class="event"><time>\${esc(t.at.replace('T',' ').slice(0,16))}</time><div><b>\${esc(t.actor||'system')}</b> \${esc(timelineLabel(t))}</div></div>\`).join('')+'</div>':'<div class="okline">No previous environment changes recorded.</div>';
|
|
439
455
|
const intentsHtml=intents.length?'<div class="timeline">'+intents.slice(-6).reverse().map(i=>\`<div class="event"><time>\${esc(i.at.replace('T',' ').slice(0,16))}</time><div><b>\${esc(i.actor)}</b> plans \${esc(i.action)}</div></div>\`).join('')+'</div>':'<div class="okline">No pending agent intents recorded.</div>';
|
|
@@ -549,7 +565,7 @@ document.getElementById('app').innerHTML=\`
|
|
|
549
565
|
<div style="height:14px"></div>
|
|
550
566
|
\${card('AI Handoff',reviewRequired?'<span class="pill warn">review</span>':'<span class="pill">ready</span>',handoffHtml)}
|
|
551
567
|
<div style="height:14px"></div>
|
|
552
|
-
\${card('Agent Pointers','<span class="pill">'+
|
|
568
|
+
\${card('Agent Pointers','<span class="pill">'+agentPointerCount+' installed</span>','<div class="agents">'+agentCards+'</div>')}
|
|
553
569
|
<div style="height:14px"></div>
|
|
554
570
|
\${card('Snapshot','',\`<table><tr><th>OS</th><td>\${esc(manifest.os.platform)} \${esc(manifest.os.release)} \${esc(manifest.os.arch)}</td></tr><tr><th>Shell</th><td>\${esc(manifest.os.shell||'unknown')}</td></tr><tr><th>Workspace</th><td><div class="path">\${esc(manifest.workspace.path)}</div></td></tr></table>\`)}
|
|
555
571
|
</aside>
|