aienvmp 0.1.39 → 0.1.40

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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.40
4
+
5
+ - Added dependency handoff summaries so the next AI receives dependency read-set and protocol guidance directly in `handoff`.
6
+ - Added a compact `nextAgent` hint to status/preflight JSON for safer AI-to-AI continuation.
7
+ - Added target-level open intent coordination summaries so agents can detect dependency conflicts without parsing logs.
8
+ - Shortened the README around the 10-second AI flow, generated outputs, and advisory contract.
9
+ - Updated the dashboard handoff card with next-agent read hints, dependency files, and conflict targets.
10
+ - Printed the next-agent handoff command in the plain `status` output.
11
+
3
12
  ## 0.1.39
4
13
 
5
14
  - Added a dependency read set to preflight, `AIENV.md`, and the dashboard so agents know which manifests and lockfiles to read before package or security changes.
package/README.md CHANGED
@@ -6,123 +6,92 @@
6
6
 
7
7
  **AI Environment Map.**
8
8
 
9
- `aienvmp` is an AI-first environment map for shared coding machines.
9
+ `aienvmp` is a lightweight env map and light SBOM for shared AI coding machines.
10
10
 
11
- It helps Codex, Claude, Gemini, and humans avoid silent Node, Python, package manager, dependency, Docker, and security drift.
11
+ It helps Codex, Claude, Gemini, and humans avoid silent runtime, package manager, dependency, Docker, and security drift.
12
12
 
13
- Core loop: scan once, link runtime/dependency/security context, give AI a shared decision contract with a light SBOM summary, and hand off safe next steps.
14
-
15
- ## Quick Start
13
+ ## 10-Second Use
16
14
 
17
15
  ```bash
18
16
  npx aienvmp sync
19
17
  npx aienvmp status
20
- npx aienvmp context
21
- npx aienvmp plan
22
- npx aienvmp handoff
23
- ```
24
-
25
- 10-second AI flow: `aienvmp status --write` -> `aienvmp context --json` -> intent before environment changes.
26
- Use `--dir <workspace>` before or after the command when an AI or CI process runs outside the target project.
27
-
28
- Optional deeper read-only checks:
29
-
30
- ```bash
31
- npx aienvmp sync --deep
32
- npx aienvmp sync --security
18
+ npx aienvmp context --json
33
19
  ```
34
20
 
35
- ## AI Usage
36
-
37
- Tell each agent to read `aienvmp context --json` before environment changes.
21
+ Before environment changes:
38
22
 
39
23
  ```bash
40
- npx aienvmp context --json
41
- npx aienvmp intent --actor agent:codex --action "upgrade node" --target node
42
- npx aienvmp record --actor agent:codex --summary "updated .nvmrc" --target node
24
+ npx aienvmp intent --actor agent:codex --action "change dependency" --target dependency
25
+ npx aienvmp record --actor agent:codex --summary "dependency-change" --target dependency
43
26
  npx aienvmp handoff --record --actor agent:codex
44
27
  ```
45
28
 
46
- ## Output
29
+ Use `--dir <workspace>` when AI or CI runs outside the target project.
30
+
31
+ ## What It Creates
47
32
 
48
33
  ```text
49
- AIENV.md
50
- .aienvmp/manifest.json
51
- .aienvmp/status.json # first file for AI: clear/review, next command, strict advice
52
- .aienvmp/intents.jsonl
53
- .aienvmp/timeline.jsonl
54
- .aienvmp/plan.json
55
- .aienvmp/plan.md # read-only plan with dependency protocol
56
- .aienvmp/dashboard.html # includes dependencies, plan, remediation, and environment cards
34
+ AIENV.md # Markdown env map for AI agents
35
+ .aienvmp/status.json # first AI read: clear/review, next command, nextAgent hint
36
+ .aienvmp/manifest.json # runtime map + light SBOM
37
+ .aienvmp/intents.jsonl # planned env changes
38
+ .aienvmp/timeline.jsonl # append-only change ledger
39
+ .aienvmp/plan.md # read-only action plan
40
+ .aienvmp/dashboard.html # human dashboard
57
41
  ```
58
42
 
59
- `AIENV.md` includes the 10-second AI flow and recommended intent targets for Markdown-first agents.
43
+ ## AI Contract
60
44
 
61
- Trust states are machine-readable: `observed`, `planned`, `changed`, `review`, `verified`, `stale`.
62
- `status.json` also lists AI read order, artifact paths, and safe commands.
63
- `status`, `context`, `plan`, and `handoff` share the same AI preflight contract.
64
- Preflight also recommends the intent target, so agents do not guess between runtime, package manager, dependency, Docker, or coordination changes.
65
- It also lists dependency manifests and lockfiles to read before package or security changes.
66
- Dependency and security changes stay advisory: record dependency intent, refresh with `sync`, then record what changed.
67
- Dependency records also trigger handoff/coordination warnings for the next agent.
68
- The dashboard shows the same intent target guidance for human review.
69
-
70
- AI agents can observe, plan, and record. Only a human or CI should mark environment facts as verified.
45
+ - `status`, `context`, `plan`, and `handoff` share one preflight contract.
46
+ - `status.json.nextAgent` tells the next AI what to read and whether to review first.
47
+ - `dependencyReadSet` lists manifests and lockfiles before package or security changes.
48
+ - `coordination.conflictTargets` shows where multiple agents are planning changes.
49
+ - `handoff` carries dependency read-set and protocol guidance for the next AI.
50
+ - Everything is advisory by default; strict failure is opt-in with `doctor --strict`.
71
51
 
72
52
  ## Agent Files
73
53
 
74
- `aienvmp` does not replace AGENTS.md. It gives AGENTS.md a live environment source of truth.
54
+ `aienvmp` does not replace AGENTS.md, CLAUDE.md, or GEMINI.md. It gives them a live environment source of truth.
75
55
 
76
56
  ```bash
77
57
  npx aienvmp snippet agents
58
+ npx aienvmp snippet claude
59
+ npx aienvmp snippet gemini
78
60
  ```
79
61
 
80
- ## CI Usage
62
+ ## Commands
63
+
64
+ ```bash
65
+ aienvmp sync # update env map, status, ledger, dashboard
66
+ aienvmp status --write # refresh compact AI status
67
+ aienvmp context --json # AI decision contract
68
+ aienvmp plan --write # read-only action plan
69
+ aienvmp handoff --record # next-agent summary
70
+ aienvmp intent # record planned env change
71
+ aienvmp record # record what changed
72
+ aienvmp doctor --strict security|policy|coordination|all
73
+ ```
81
74
 
82
- Use the GitHub Action to write the env map, plan, dashboard, and optional strict checks. See [examples/github-action.yml](examples/github-action.yml).
83
- CI also writes `.aienvmp/status.json` for a compact AI-readable result.
84
- The dashboard shows which strict scopes are CI-ready before you enforce them.
75
+ ## CI
85
76
 
86
77
  ```yaml
87
78
  - uses: soovwv/aienvmp@main
88
79
  with:
89
80
  write-status: "true"
90
81
  write-plan: "true"
91
- strict: "off" # security, policy, coordination, all, or off
82
+ strict: "off"
92
83
  ```
93
84
 
94
- ## Commands
95
-
96
- ```bash
97
- aienvmp sync # update env map, light SBOM, status, ledger, dashboard
98
- aienvmp status --write # refresh .aienvmp/status.json only
99
- aienvmp context # AI preflight brief
100
- aienvmp context --json # AI decision contract + actions + compact step summary
101
- aienvmp plan # read-only AI action plan using the same decision contract
102
- aienvmp handoff # next-agent handoff summary using the same decision contract
103
- aienvmp intent # record a planned env change
104
- aienvmp record # record what changed
105
- aienvmp doctor --ci # strict CI check for all warnings
106
- aienvmp doctor --strict security # fail only scoped warnings
107
- ```
85
+ See [examples/github-action.yml](examples/github-action.yml).
108
86
 
109
87
  ## Principles
110
88
 
111
- - simple by default
112
- - AI-first
113
- - lightweight
114
- - read-only planning, no automatic fixes
115
- - one advisory engine, optional enforcement with `doctor --ci`
116
- - scoped enforcement with `doctor --strict security|policy|coordination|all`
117
- - context and plan expose suggested strict scopes for CI
118
- - dashboard and preflight explain advisory default vs optional strict mode
119
- - non-blocking unless strict mode is explicitly requested
120
- - security checks are opt-in and read-only
121
- - light SBOM is generated from project files and optional scanner summaries
122
- - dependency change hints point AI agents to the relevant manifest before edits
123
- - lockfiles are detected read-only and shown before dependency edits
124
- - package manager policy is inferred from lockfiles to avoid accidental npm/pnpm/yarn drift
125
- - dashboard mirrors AI-facing SBOM hints so humans can review the same dependency context
89
+ - simple commands
90
+ - AI-first outputs
91
+ - lightweight, read-only scanning
92
+ - light SBOM from project files
93
+ - advisory locally, strict only when requested
94
+ - humans or CI verify; AI agents observe, plan, record, and hand off
126
95
 
127
96
  ## Development
128
97
 
@@ -132,8 +101,6 @@ npm run smoke
132
101
  npm pack --dry-run
133
102
  ```
134
103
 
135
- ## Links
136
-
137
104
  [Roadmap](ROADMAP.md) / [Security](SECURITY.md) / [Troubleshooting](TROUBLESHOOTING.md) / [Bugfix Log](BUGFIXES.md) / [Contributing](CONTRIBUTING.md)
138
105
 
139
106
  Apache-2.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aienvmp",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "AI-first environment maps and lightweight runtime SBOMs for shared development machines.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,11 +46,12 @@ async function recordHandoff(file, handoff, actor) {
46
46
  export function buildHandoff(manifest, timeline = [], warnings = [], intents = [], policy = {}) {
47
47
  const reviewRequired = warnings.length > 0 || intents.length > 0;
48
48
  const actions = recommendedActions(manifest, { warnings, intents });
49
+ const preflight = buildPreflight(manifest, warnings, intents);
49
50
  return {
50
51
  status: reviewRequired ? "review-required" : "clear",
51
52
  trust: manifest.trust || {},
52
53
  schemaVersion: manifest.schemaVersion || 1,
53
- preflight: buildPreflight(manifest, warnings, intents),
54
+ preflight,
54
55
  decision: aiDecision(warnings, intents),
55
56
  workspace: manifest.workspace,
56
57
  safeRuntime: {
@@ -60,6 +61,7 @@ export function buildHandoff(manifest, timeline = [], warnings = [], intents = [
60
61
  },
61
62
  inventory: inventorySummary(manifest.inventory),
62
63
  security: securitySummary(manifest.security),
64
+ dependencyHandoff: dependencyHandoffSummary(preflight),
63
65
  policy: {
64
66
  node: policy.node || "not set",
65
67
  python: policy.python || "not set",
@@ -82,6 +84,20 @@ export function buildHandoff(manifest, timeline = [], warnings = [], intents = [
82
84
  };
83
85
  }
84
86
 
87
+ function dependencyHandoffSummary(preflight = {}) {
88
+ const protocol = preflight.dependencyChangeProtocol || {};
89
+ return {
90
+ readSet: (preflight.dependencyReadSet || []).slice(0, 5),
91
+ protocol: {
92
+ mode: protocol.mode || "advisory",
93
+ packageManagerPolicy: protocol.packageManagerPolicy || "not-detected",
94
+ recordIntent: protocol.commands?.recordIntent || "aienvmp intent --actor agent:id --action planned-change --target dependency",
95
+ recordAfterChange: protocol.commands?.recordAfterChange || "aienvmp record --actor agent:id --summary dependency-change --target dependency",
96
+ handoff: protocol.commands?.handoff || "aienvmp handoff --record --actor agent:id"
97
+ }
98
+ };
99
+ }
100
+
85
101
  function securitySummary(security = {}) {
86
102
  return {
87
103
  mode: security.mode || "basic",
@@ -25,6 +25,7 @@ export async function statusWorkspace(args) {
25
25
  console.log(`next: ${output.nextCommand}`);
26
26
  console.log(`ai: ${output.quickstart.readFirst} -> ${output.quickstart.detailCommand}`);
27
27
  console.log(`intent: ${output.intentTargets[0]?.command || output.commands.recordIntent}`);
28
+ console.log(`handoff: ${output.nextAgent.handoffCommand}`);
28
29
  console.log(`strict: ${output.enforcement.recommendedCommand}`);
29
30
  if (artifact) console.log(`status: ${artifact}`);
30
31
  }
package/src/preflight.js CHANGED
@@ -11,6 +11,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
11
11
  const intentTargets = recommendedIntentTargets(manifest, warnings, intents);
12
12
  const dependencyReadSet = dependencyPreflightReadSet(manifest);
13
13
  const dependencyChangeProtocol = dependencyProtocol(manifest, dependencyReadSet);
14
+ const coordination = coordinationSummary(intents);
14
15
  return {
15
16
  schemaVersion: 1,
16
17
  state,
@@ -47,6 +48,8 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
47
48
  environmentChanges: decision.canChangeEnvironmentWithoutReview ? "allowed" : "intent-and-review-first"
48
49
  },
49
50
  quickstart: agentQuickstart(decision.reviewRequired),
51
+ nextAgent: nextAgentHint(state, dependencyReadSet, dependencyChangeProtocol),
52
+ coordination,
50
53
  intentTargets,
51
54
  dependencyReadSet,
52
55
  dependencyChangeProtocol,
@@ -72,6 +75,56 @@ export function buildPreflight(manifest = {}, warnings = [], intents = []) {
72
75
  };
73
76
  }
74
77
 
78
+ function coordinationSummary(intents = []) {
79
+ const byTarget = new Map();
80
+ for (const intent of intents) {
81
+ const target = normalizeTarget(intent.target || targetFromText(intent.action) || "environment") || "environment";
82
+ const item = byTarget.get(target) || { target, count: 0, actors: [], actions: [], conflict: false };
83
+ item.count += 1;
84
+ if (intent.actor && !item.actors.includes(intent.actor)) item.actors.push(intent.actor);
85
+ if (intent.action) item.actions.push(intent.action);
86
+ byTarget.set(target, item);
87
+ }
88
+ const targets = [...byTarget.values()].map((item) => ({
89
+ target: item.target,
90
+ count: item.count,
91
+ actors: item.actors.slice(0, 5),
92
+ actions: item.actions.slice(-3),
93
+ conflict: item.count > 1 && item.actors.length > 1
94
+ }));
95
+ const conflictTargets = targets.filter((item) => item.conflict).map((item) => item.target);
96
+ return {
97
+ openIntentCount: intents.length,
98
+ targets,
99
+ conflictTargets,
100
+ next: conflictTargets.length
101
+ ? "Review or resolve conflicting intents before environment changes."
102
+ : intents.length
103
+ ? "Check open intents before environment changes."
104
+ : "No open environment intents."
105
+ };
106
+ }
107
+
108
+ function nextAgentHint(state, dependencyReadSet = [], dependencyChangeProtocol = {}) {
109
+ const firstDependency = dependencyReadSet[0];
110
+ const dependencyFiles = firstDependency
111
+ ? [firstDependency.manifest, ...(firstDependency.lockfiles || [])].filter(Boolean)
112
+ : [];
113
+ return {
114
+ handoffCommand: dependencyChangeProtocol.commands?.handoff || "aienvmp handoff --record --actor agent:id",
115
+ readFirst: ".aienvmp/status.json",
116
+ readNext: "aienvmp context --json",
117
+ reviewState: state,
118
+ dependencyFiles,
119
+ dependencyProtocol: dependencyChangeProtocol.commands?.recordIntent
120
+ ? "record dependency intent, sync after change, then record dependency-change"
121
+ : "no dependency protocol detected",
122
+ rule: state === "clear"
123
+ ? "Next AI may continue project-local work; record intent before environment changes."
124
+ : "Next AI should review warnings or open intents before environment changes."
125
+ };
126
+ }
127
+
75
128
  function dependencyProtocol(manifest = {}, dependencyReadSet = []) {
76
129
  const pmPolicy = manifest.lightSbom?.packageManagerPolicy || {};
77
130
  return {
package/src/render.js CHANGED
@@ -205,6 +205,9 @@ export function renderHandoff(handoff) {
205
205
  "Recommended actions:",
206
206
  ...(handoff.recommendedActions?.length ? handoff.recommendedActions.map((item) => `- [${item.priority}] ${item.summary}${item.command ? ` (${item.command})` : ""}`) : ["- none"]),
207
207
  "",
208
+ "Dependency handoff:",
209
+ ...dependencyHandoffLines(handoff.dependencyHandoff),
210
+ "",
208
211
  "Recent changes:",
209
212
  ...(handoff.recentChanges.length ? handoff.recentChanges.map((t) => `- ${formatTimeline(t)}`) : ["- none"]),
210
213
  "",
@@ -217,6 +220,24 @@ export function renderHandoff(handoff) {
217
220
  return lines.join("\n");
218
221
  }
219
222
 
223
+ function dependencyHandoffLines(dependencyHandoff = {}) {
224
+ const readSet = dependencyHandoff.readSet || [];
225
+ const protocol = dependencyHandoff.protocol || {};
226
+ const lines = [];
227
+ if (readSet.length) {
228
+ for (const item of readSet.slice(0, 3)) {
229
+ const files = [item.manifest, ...(item.lockfiles || [])].filter(Boolean).join(", ");
230
+ lines.push(`- Read: ${files || "dependency files"} (${item.ecosystem || "deps"}/${item.manager || "unknown"})`);
231
+ }
232
+ } else {
233
+ lines.push("- Read: no dependency files detected");
234
+ }
235
+ lines.push(`- Intent: ${protocol.recordIntent || "aienvmp intent --actor agent:id --action planned-change --target dependency"}`);
236
+ lines.push(`- After change: ${protocol.recordAfterChange || "aienvmp record --actor agent:id --summary dependency-change --target dependency"}`);
237
+ lines.push(`- Handoff: ${protocol.handoff || "aienvmp handoff --record --actor agent:id"}`);
238
+ return lines;
239
+ }
240
+
220
241
  export function renderPlan(plan) {
221
242
  const lines = [
222
243
  "# AI Environment Plan",
@@ -398,7 +419,12 @@ const trustState=manifest.trust?.state||'observed';
398
419
  const nextAction=reviewRequired?'Review before environment changes':'Proceed with project-local work';
399
420
  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>\`;
400
421
  const driftLabel=warnings.length?'detected':'none';
401
- const handoffHtml=\`<table><tr><th>Status</th><td>\${reviewRequired?'review-required':'clear'}</td></tr><tr><th>Trust</th><td><code>\${esc(trustState)}</code></td></tr><tr><th>Node</th><td><code>\${esc(manifest.runtimes.node||'not detected')}</code></td></tr><tr><th>Python</th><td><code>\${esc(manifest.runtimes.python||manifest.runtimes.python3||'not detected')}</code></td></tr><tr><th>Docker</th><td>\${manifest.containers?.docker?'available':'not detected'}</td></tr><tr><th>Next</th><td>\${reviewRequired?'Review warnings and open intents':'Continue project-local work'}</td></tr></table>\`;
422
+ const nextAgent=manifest.preflight?.nextAgent||{};
423
+ const coordination=manifest.preflight?.coordination||{};
424
+ const conflictTargets=coordination.conflictTargets||[];
425
+ const handoffFiles=nextAgent.dependencyFiles?.length?nextAgent.dependencyFiles:(dependencyReadSet[0]?[dependencyReadSet[0].manifest,...(dependencyReadSet[0].lockfiles||[])].filter(Boolean):[]);
426
+ const handoffNext=nextAgent.rule||(reviewRequired?'Review warnings and open intents':'Continue project-local work');
427
+ const handoffHtml=\`<table><tr><th>Status</th><td>\${reviewRequired?'review-required':'clear'}</td></tr><tr><th>Trust</th><td><code>\${esc(trustState)}</code></td></tr><tr><th>Read first</th><td><code>\${esc(nextAgent.readFirst||'.aienvmp/status.json')}</code></td></tr><tr><th>Dependency files</th><td>\${handoffFiles.length?'<code>'+esc(handoffFiles.join(', '))+'</code>':'none'}</td></tr><tr><th>Conflicts</th><td>\${conflictTargets.length?'<code>'+esc(conflictTargets.join(', '))+'</code>':'none'}</td></tr><tr><th>Next</th><td>\${esc(handoffNext)}</td></tr></table>\`;
402
428
  document.getElementById('app').innerHTML=\`
403
429
  <header>
404
430
  <div>