aienvmp 0.1.49 → 0.1.51
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 +18 -0
- package/CHANGELOG.md +21 -0
- package/README.md +9 -2
- package/action.yml +14 -0
- package/examples/github-action.yml +2 -0
- package/package.json +1 -1
- package/src/cli.js +8 -3
- package/src/commands/summary.js +118 -0
- package/src/commands/sync.js +4 -1
- package/src/contract.js +6 -0
- package/src/fsutil.js +5 -1
- package/src/paths.js +4 -0
- package/src/preflight.js +3 -0
- package/src/render.js +18 -6
|
@@ -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
|
@@ -82,6 +82,24 @@ Short record of bugs, fixes, and follow-up checks.
|
|
|
82
82
|
- Fix: the Action now has `write-sbom` and the example uploads both native and CycloneDX-lite SBOM artifacts.
|
|
83
83
|
- Verification: Action tests cover input metadata, SBOM write commands, and example artifact paths.
|
|
84
84
|
|
|
85
|
+
### CI and AI review still needed a short handoff view
|
|
86
|
+
|
|
87
|
+
- Issue: `status.json` was AI-friendly, but GitHub Actions and quick human review still required opening JSON artifacts or the dashboard.
|
|
88
|
+
- Fix: `aienvmp summary` now writes `.aienvmp/summary.md`, `sync` creates it by default, and the GitHub Action appends it to `GITHUB_STEP_SUMMARY`.
|
|
89
|
+
- Verification: tests cover summary rendering, sync artifact creation, schema metadata, Action wiring, and example upload paths.
|
|
90
|
+
|
|
91
|
+
### Windows-created JSON files could be missed
|
|
92
|
+
|
|
93
|
+
- Issue: UTF-8 BOM JSON files created by some Windows tools could fail JSON parsing and make dependency snapshots look empty.
|
|
94
|
+
- Fix: `readJson` now strips a leading UTF-8 BOM before parsing.
|
|
95
|
+
- Verification: regression tests cover BOM JSON parsing and Windows smoke testing confirmed dependency counts in `summary.md`.
|
|
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
|
+
|
|
85
103
|
## Template
|
|
86
104
|
|
|
87
105
|
### Title
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.51
|
|
4
|
+
|
|
5
|
+
- Updated Codex/Claude/Gemini pointer snippets to use the current `status -> summary.md -> context` read order.
|
|
6
|
+
- Added agent-specific actor examples for Codex, Claude, and Gemini snippet output.
|
|
7
|
+
- Added dependency and lockfile changes to the snippet environment-change scope.
|
|
8
|
+
- Updated the packaged Codex skill to prefer `status --write`, `summary.md`, and `checkpoint`.
|
|
9
|
+
- Added `.aienvmp/summary.md` to the shared preflight read order and next-agent hint.
|
|
10
|
+
- Added a Dependency changes section to `summary.md` with read files, intent command, checkpoint command, and package-manager policy.
|
|
11
|
+
- Updated README agent-file guidance and added regression coverage for the AI snippet and summary protocol.
|
|
12
|
+
|
|
13
|
+
## 0.1.50
|
|
14
|
+
|
|
15
|
+
- Added `aienvmp summary` for a compact Markdown AI/CI handoff view.
|
|
16
|
+
- Added `.aienvmp/summary.md` writing through the default `sync` flow.
|
|
17
|
+
- Added `summary` to preflight artifacts and the stable output contract.
|
|
18
|
+
- Added a GitHub Action `write-summary` input.
|
|
19
|
+
- Appended `.aienvmp/summary.md` to GitHub Step Summary when the Action runs in GitHub Actions.
|
|
20
|
+
- Updated the GitHub Action example and README to include the summary artifact.
|
|
21
|
+
- Fixed UTF-8 BOM JSON parsing so Windows-created `package.json` files are scanned correctly.
|
|
22
|
+
- Added regression tests for summary rendering, sync output, schema metadata, Action Step Summary wiring, and BOM JSON parsing.
|
|
23
|
+
|
|
3
24
|
## 0.1.49
|
|
4
25
|
|
|
5
26
|
- Added a `write-sbom` GitHub Action input for explicit SBOM artifact generation.
|
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ Warnings are advisory by default. Use `doctor --strict <scope>` only when you wa
|
|
|
34
34
|
```text
|
|
35
35
|
AIENV.md # Markdown env map for AI agents
|
|
36
36
|
.aienvmp/status.json # first AI read: clear/review, next command, nextAgent hint
|
|
37
|
+
.aienvmp/summary.md # compact AI/CI summary
|
|
37
38
|
.aienvmp/manifest.json # runtime map + light SBOM
|
|
38
39
|
.aienvmp/sbom.json # standalone AI-readable light SBOM
|
|
39
40
|
.aienvmp/sbom.cdx.json # CycloneDX-lite export from project manifests
|
|
@@ -47,6 +48,7 @@ AIENV.md # Markdown env map for AI agents
|
|
|
47
48
|
|
|
48
49
|
- `status`, `context`, `plan`, and `handoff` share one preflight contract.
|
|
49
50
|
- `schema --json` prints the stable AI-readable output contract without scanning.
|
|
51
|
+
- `summary.md` is the short CI/AI handoff view.
|
|
50
52
|
- `status.json.nextAgent` tells the next AI what to read and whether to review first.
|
|
51
53
|
- `dependencyReadSet` lists manifests and lockfiles before package or security changes.
|
|
52
54
|
- `sbomRisk` gives AI a compact light-SBOM risk level, signals, and next command.
|
|
@@ -63,16 +65,20 @@ AIENV.md # Markdown env map for AI agents
|
|
|
63
65
|
`aienvmp` does not replace AGENTS.md, CLAUDE.md, or GEMINI.md. It gives them a live environment source of truth.
|
|
64
66
|
|
|
65
67
|
```bash
|
|
68
|
+
npx aienvmp snippet codex
|
|
66
69
|
npx aienvmp snippet agents
|
|
67
70
|
npx aienvmp snippet claude
|
|
68
71
|
npx aienvmp snippet gemini
|
|
69
72
|
```
|
|
70
73
|
|
|
74
|
+
Snippets point each AI to `status`, `summary.md`, `context --json`, intent, and checkpoint without taking over the instruction file.
|
|
75
|
+
|
|
71
76
|
## Commands
|
|
72
77
|
|
|
73
78
|
```bash
|
|
74
|
-
aienvmp sync # update env map, status,
|
|
79
|
+
aienvmp sync # update env map, status, summary, SBOM, dashboard
|
|
75
80
|
aienvmp status --write # refresh compact AI status
|
|
81
|
+
aienvmp summary --write # refresh compact Markdown summary
|
|
76
82
|
aienvmp context --json # AI decision contract
|
|
77
83
|
aienvmp sbom --json # standalone light SBOM
|
|
78
84
|
aienvmp sbom --format cyclonedx-lite --json
|
|
@@ -87,7 +93,7 @@ aienvmp doctor --strict security|policy|coordination|all
|
|
|
87
93
|
|
|
88
94
|
## CI
|
|
89
95
|
|
|
90
|
-
The GitHub Action writes status, schema, doctor, plan, SBOM, and dashboard artifacts. `strict: "off"` reports warnings without failing the job.
|
|
96
|
+
The GitHub Action writes status, summary, schema, doctor, plan, SBOM, and dashboard artifacts. `strict: "off"` reports warnings without failing the job.
|
|
91
97
|
|
|
92
98
|
```yaml
|
|
93
99
|
- uses: soovwv/aienvmp@main
|
|
@@ -95,6 +101,7 @@ The GitHub Action writes status, schema, doctor, plan, SBOM, and dashboard artif
|
|
|
95
101
|
write-status: "true"
|
|
96
102
|
write-plan: "true"
|
|
97
103
|
write-sbom: "true"
|
|
104
|
+
write-summary: "true"
|
|
98
105
|
strict: "off"
|
|
99
106
|
```
|
|
100
107
|
|
package/action.yml
CHANGED
|
@@ -31,6 +31,10 @@ inputs:
|
|
|
31
31
|
description: Write standalone light SBOM and CycloneDX-lite artifacts
|
|
32
32
|
required: false
|
|
33
33
|
default: "true"
|
|
34
|
+
write-summary:
|
|
35
|
+
description: Write compact Markdown summary and append it to GitHub Step Summary
|
|
36
|
+
required: false
|
|
37
|
+
default: "true"
|
|
34
38
|
|
|
35
39
|
runs:
|
|
36
40
|
using: composite
|
|
@@ -77,6 +81,16 @@ runs:
|
|
|
77
81
|
node "$GITHUB_ACTION_PATH/bin/aienvmp.js" sbom --dir "${{ inputs.directory }}" --format cyclonedx-lite --write --quiet
|
|
78
82
|
fi
|
|
79
83
|
|
|
84
|
+
- name: Write AI summary
|
|
85
|
+
shell: bash
|
|
86
|
+
run: |
|
|
87
|
+
if [ "${{ inputs.write-summary }}" = "true" ]; then
|
|
88
|
+
node "$GITHUB_ACTION_PATH/bin/aienvmp.js" summary --dir "${{ inputs.directory }}" --write --quiet
|
|
89
|
+
if [ -n "$GITHUB_STEP_SUMMARY" ]; then
|
|
90
|
+
cat "${{ inputs.directory }}/.aienvmp/summary.md" >> "$GITHUB_STEP_SUMMARY"
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
80
94
|
- name: Doctor
|
|
81
95
|
shell: bash
|
|
82
96
|
run: |
|
|
@@ -17,6 +17,7 @@ jobs:
|
|
|
17
17
|
write-schema: "true"
|
|
18
18
|
write-doctor-json: "true"
|
|
19
19
|
write-sbom: "true"
|
|
20
|
+
write-summary: "true"
|
|
20
21
|
strict: "off" # security, policy, coordination, all, or off
|
|
21
22
|
|
|
22
23
|
- uses: actions/upload-artifact@v4
|
|
@@ -27,6 +28,7 @@ jobs:
|
|
|
27
28
|
AIENV.md
|
|
28
29
|
.aienvmp/manifest.json
|
|
29
30
|
.aienvmp/status.json
|
|
31
|
+
.aienvmp/summary.md
|
|
30
32
|
.aienvmp/sbom.json
|
|
31
33
|
.aienvmp/sbom.cdx.json
|
|
32
34
|
.aienvmp/schema.json
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ import { statusWorkspace } from "./commands/status.js";
|
|
|
16
16
|
import { schemaWorkspace } from "./commands/schema.js";
|
|
17
17
|
import { checkpointWorkspace } from "./commands/checkpoint.js";
|
|
18
18
|
import { sbomWorkspace } from "./commands/sbom.js";
|
|
19
|
+
import { summaryWorkspace } from "./commands/summary.js";
|
|
19
20
|
import { readFileSync } from "node:fs";
|
|
20
21
|
|
|
21
22
|
const commands = new Map([
|
|
@@ -36,7 +37,8 @@ const commands = new Map([
|
|
|
36
37
|
["status", statusWorkspace],
|
|
37
38
|
["schema", schemaWorkspace],
|
|
38
39
|
["checkpoint", checkpointWorkspace],
|
|
39
|
-
["sbom", sbomWorkspace]
|
|
40
|
+
["sbom", sbomWorkspace],
|
|
41
|
+
["summary", summaryWorkspace]
|
|
40
42
|
]);
|
|
41
43
|
|
|
42
44
|
const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
@@ -115,16 +117,18 @@ Usage:
|
|
|
115
117
|
aienvmp checkpoint [--dir .] --actor agent:id --summary "what changed" [--target dependency] [--json]
|
|
116
118
|
aienvmp plan [--dir .] [--json] [--write]
|
|
117
119
|
aienvmp sbom [--dir .] [--json] [--write]
|
|
120
|
+
aienvmp summary [--dir .] [--write]
|
|
118
121
|
aienvmp schema [--json]
|
|
119
122
|
|
|
120
123
|
Common:
|
|
121
|
-
aienvmp sync update AIENV.md, manifest, status, ledger, intents, and dashboard
|
|
124
|
+
aienvmp sync update AIENV.md, manifest, status, summary, SBOM, ledger, intents, and dashboard
|
|
122
125
|
aienvmp status print one simple environment decision; --write saves .aienvmp/status.json
|
|
123
126
|
aienvmp context print the AI preflight brief
|
|
124
127
|
aienvmp handoff print the next-agent handoff summary
|
|
125
128
|
aienvmp checkpoint record, sync, status, and handoff after an env change
|
|
126
129
|
aienvmp plan print a read-only AI environment action plan
|
|
127
130
|
aienvmp sbom print/write standalone light SBOM artifact
|
|
131
|
+
aienvmp summary print/write a compact Markdown summary for AI and CI
|
|
128
132
|
aienvmp schema print the stable AI-readable output contract
|
|
129
133
|
aienvmp snippet print an AGENTS.md pointer snippet
|
|
130
134
|
aienvmp dash regenerate/open the lightweight dashboard
|
|
@@ -136,11 +140,12 @@ Advanced:
|
|
|
136
140
|
aienvmp resolve [--dir .] --actor human:you --id <intent-id> [--status resolved|cancelled]
|
|
137
141
|
aienvmp record [--dir .] --actor agent:codex --summary "updated .nvmrc" [--target node] [--before 20] [--after 24]
|
|
138
142
|
aienvmp checkpoint [--dir .] --actor agent:codex --summary "updated dependency" [--target dependency]
|
|
139
|
-
aienvmp snippet [agents|claude|gemini] [--write AGENTS.md]
|
|
143
|
+
aienvmp snippet [agents|codex|claude|gemini] [--write AGENTS.md]
|
|
140
144
|
aienvmp compile [--dir .]
|
|
141
145
|
aienvmp diff [--dir .]
|
|
142
146
|
aienvmp doctor [--dir .] [--json] [--ci] [--strict security|policy|coordination|all]
|
|
143
147
|
aienvmp sbom [--dir .] [--json] [--write]
|
|
148
|
+
aienvmp summary [--dir .] [--write]
|
|
144
149
|
aienvmp dash [--dir .] [--open]
|
|
145
150
|
`);
|
|
146
151
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readJson } from "../fsutil.js";
|
|
4
|
+
import { manifestPath, statusJsonPath, summaryMdPath, workspaceDir } from "../paths.js";
|
|
5
|
+
import { statusWorkspace } from "./status.js";
|
|
6
|
+
|
|
7
|
+
export async function summaryWorkspace(args) {
|
|
8
|
+
const dir = workspaceDir(args);
|
|
9
|
+
let status = await readJson(statusJsonPath(dir));
|
|
10
|
+
if (!status) {
|
|
11
|
+
status = await statusWorkspace({ ...args, dir, json: false, write: true, quiet: true });
|
|
12
|
+
}
|
|
13
|
+
const manifest = await readJson(manifestPath(dir), {});
|
|
14
|
+
const markdown = renderSummary(status, manifest);
|
|
15
|
+
const artifact = args.write ? await writeSummaryArtifact(dir, markdown) : "";
|
|
16
|
+
const output = { artifact, summary: markdown, state: status.state || "unknown", sbomRisk: status.sbomRisk || {}, nextCommand: status.nextCommand || "" };
|
|
17
|
+
|
|
18
|
+
if (args.json) {
|
|
19
|
+
console.log(JSON.stringify(output, null, 2));
|
|
20
|
+
} else if (!args.quiet) {
|
|
21
|
+
console.log(markdown.trimEnd());
|
|
22
|
+
if (artifact) console.log(`\nsummary: ${artifact}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return output;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function writeSummaryArtifact(dir, markdown) {
|
|
29
|
+
const out = summaryMdPath(dir);
|
|
30
|
+
await fs.mkdir(path.dirname(out), { recursive: true });
|
|
31
|
+
await fs.writeFile(out, `${markdown.trimEnd()}\n`, "utf8");
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function renderSummary(status = {}, manifest = {}) {
|
|
36
|
+
const counts = status.counts || {};
|
|
37
|
+
const sbomRisk = status.sbomRisk || manifest.lightSbom?.riskSummary || {};
|
|
38
|
+
const coordination = status.coordination || {};
|
|
39
|
+
const activity = status.agentActivity || {};
|
|
40
|
+
const workspace = manifest.workspace?.root || manifest.workspace?.name || ".";
|
|
41
|
+
const next = status.nextCommand || status.decision?.nextCommand || "aienvmp status";
|
|
42
|
+
const readFirst = status.nextAgent?.readFirst || ".aienvmp/status.json";
|
|
43
|
+
const detail = status.quickstart?.detailCommand || "aienvmp context --json";
|
|
44
|
+
const strict = status.enforcement?.recommendedCommand || "aienvmp doctor --strict all";
|
|
45
|
+
const riskLevel = sbomRisk.level || "unknown";
|
|
46
|
+
const riskScore = valueOrZero(sbomRisk.score);
|
|
47
|
+
const scanner = sbomRisk.scanner || manifest.lightSbom?.source?.scanner || "not run";
|
|
48
|
+
const riskSignals = toList(sbomRisk.signals).slice(0, 3);
|
|
49
|
+
const conflictTargets = toList(coordination.conflictTargets);
|
|
50
|
+
const multiActorTargets = toList(activity.multiActorTargets);
|
|
51
|
+
const dependencyProtocol = status.dependencyChangeProtocol || {};
|
|
52
|
+
const dependencyCommands = dependencyProtocol.commands || {};
|
|
53
|
+
const dependencyFiles = dependencyFilesFor(status.dependencyReadSet);
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
"# aienvmp summary",
|
|
57
|
+
"",
|
|
58
|
+
`- state: ${status.state || "unknown"}`,
|
|
59
|
+
`- workspace: ${workspace}`,
|
|
60
|
+
`- warnings: ${valueOrZero(counts.warnings)} / open intents: ${valueOrZero(counts.openIntents)}`,
|
|
61
|
+
`- runtimes: ${valueOrZero(counts.runtimes)} / dependencies: ${valueOrZero(counts.dependencies)} / vulnerabilities: ${valueOrZero(counts.vulnerabilities)}`,
|
|
62
|
+
`- light SBOM risk: ${riskLevel} (${riskScore}) / scanner: ${scanner}`,
|
|
63
|
+
`- next: ${next}`,
|
|
64
|
+
`- AI read first: ${readFirst}, then ${detail}`,
|
|
65
|
+
`- mode: advisory by default; strict is opt-in with ${strict}`,
|
|
66
|
+
"",
|
|
67
|
+
"## AI handoff",
|
|
68
|
+
"",
|
|
69
|
+
`- environment changes: ${status.agentUse?.environmentChanges || "intent-and-review-first"}`,
|
|
70
|
+
`- coordination: ${coordination.next || "No open environment intents."}`,
|
|
71
|
+
`- recent agent activity: ${activity.next || "No environment records need coordination."}`,
|
|
72
|
+
`- conflict targets: ${conflictTargets.length ? conflictTargets.join(", ") : "none"}`,
|
|
73
|
+
`- multi-actor targets: ${multiActorTargets.length ? multiActorTargets.join(", ") : "none"}`,
|
|
74
|
+
"",
|
|
75
|
+
"## SBOM",
|
|
76
|
+
"",
|
|
77
|
+
`- source: ${manifest.lightSbom?.source?.dependencies || "project manifests"}`,
|
|
78
|
+
`- confidence: transitive ${manifest.lightSbom?.confidence?.transitiveDependencies || "not-resolved"}`,
|
|
79
|
+
`- signals: ${riskSignals.length ? riskSignals.join("; ") : "none"}`,
|
|
80
|
+
`- verify: ${sbomRisk.next || "Use a dedicated scanner for security decisions."}`,
|
|
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
|
+
"",
|
|
89
|
+
"## Artifacts",
|
|
90
|
+
"",
|
|
91
|
+
"- AIENV.md",
|
|
92
|
+
"- .aienvmp/status.json",
|
|
93
|
+
"- .aienvmp/manifest.json",
|
|
94
|
+
"- .aienvmp/sbom.json",
|
|
95
|
+
"- .aienvmp/sbom.cdx.json",
|
|
96
|
+
"- .aienvmp/dashboard.html"
|
|
97
|
+
].join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function valueOrZero(value) {
|
|
101
|
+
return Number.isFinite(Number(value)) ? Number(value) : 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function toList(value) {
|
|
105
|
+
return Array.isArray(value) ? value.filter(Boolean) : [];
|
|
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/commands/sync.js
CHANGED
|
@@ -4,6 +4,7 @@ import { compileWorkspace } from "./compile.js";
|
|
|
4
4
|
import { dashWorkspace } from "./dash.js";
|
|
5
5
|
import { statusWorkspace } from "./status.js";
|
|
6
6
|
import { sbomWorkspace } from "./sbom.js";
|
|
7
|
+
import { summaryWorkspace } from "./summary.js";
|
|
7
8
|
|
|
8
9
|
export async function syncWorkspace(args) {
|
|
9
10
|
const quiet = args.quiet || args.json;
|
|
@@ -16,6 +17,7 @@ export async function syncWorkspace(args) {
|
|
|
16
17
|
const status = await statusWorkspace({ ...next, json: false, write: true, quiet: true });
|
|
17
18
|
const sbom = await sbomWorkspace({ ...next, json: false, write: true, quiet: true });
|
|
18
19
|
const cyclonedx = await sbomWorkspace({ ...next, json: false, write: true, quiet: true, format: "cyclonedx-lite" });
|
|
20
|
+
const summary = await summaryWorkspace({ ...next, json: false, write: true, quiet: true });
|
|
19
21
|
|
|
20
22
|
const result = {
|
|
21
23
|
status: "ok",
|
|
@@ -26,6 +28,7 @@ export async function syncWorkspace(args) {
|
|
|
26
28
|
status: status.artifact,
|
|
27
29
|
sbom: sbom.artifact,
|
|
28
30
|
cyclonedx: cyclonedx.artifact,
|
|
31
|
+
summary: summary.artifact,
|
|
29
32
|
dashboard: dashboard.dashboard
|
|
30
33
|
},
|
|
31
34
|
changes: scanned.changes,
|
|
@@ -35,7 +38,7 @@ export async function syncWorkspace(args) {
|
|
|
35
38
|
if (args.json) {
|
|
36
39
|
console.log(JSON.stringify(result, null, 2));
|
|
37
40
|
} else if (!quiet) {
|
|
38
|
-
console.log("sync complete: AIENV.md, manifest, status, ledger, intents, and dashboard are up to date");
|
|
41
|
+
console.log("sync complete: AIENV.md, manifest, status, SBOM, summary, ledger, intents, and dashboard are up to date");
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
return result;
|
package/src/contract.js
CHANGED
|
@@ -20,6 +20,12 @@ export function schemaContract() {
|
|
|
20
20
|
command: "aienvmp status --json",
|
|
21
21
|
contract: preflightContract()
|
|
22
22
|
},
|
|
23
|
+
summary: {
|
|
24
|
+
file: ".aienvmp/summary.md",
|
|
25
|
+
command: "aienvmp summary --write",
|
|
26
|
+
format: "markdown",
|
|
27
|
+
purpose: "Compact AI and CI step summary for quick review."
|
|
28
|
+
},
|
|
23
29
|
context: {
|
|
24
30
|
command: "aienvmp context --json",
|
|
25
31
|
rootFields: ["status", "preflight", "coordination", "decision", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
package/src/fsutil.js
CHANGED
|
@@ -12,12 +12,16 @@ export async function exists(file) {
|
|
|
12
12
|
|
|
13
13
|
export async function readJson(file, fallback = null) {
|
|
14
14
|
try {
|
|
15
|
-
return JSON.parse(await fs.readFile(file, "utf8"));
|
|
15
|
+
return JSON.parse(stripBom(await fs.readFile(file, "utf8")));
|
|
16
16
|
} catch {
|
|
17
17
|
return fallback;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function stripBom(value) {
|
|
22
|
+
return String(value).replace(/^\uFEFF/, "");
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
export async function writeJson(file, data) {
|
|
22
26
|
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
23
27
|
await fs.writeFile(file, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
package/src/paths.js
CHANGED
|
@@ -48,6 +48,10 @@ export function planMdPath(dir) {
|
|
|
48
48
|
return path.join(stateDir(dir), "plan.md");
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
export function summaryMdPath(dir) {
|
|
52
|
+
return path.join(stateDir(dir), "summary.md");
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
export function aiEnvPath(dir) {
|
|
52
56
|
return path.join(dir, "AIENV.md");
|
|
53
57
|
}
|
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,
|
|
@@ -351,6 +353,7 @@ function agentQuickstart(reviewRequired) {
|
|
|
351
353
|
export function preflightArtifacts() {
|
|
352
354
|
return {
|
|
353
355
|
status: ".aienvmp/status.json",
|
|
356
|
+
summary: ".aienvmp/summary.md",
|
|
354
357
|
envMap: "AIENV.md",
|
|
355
358
|
manifest: ".aienvmp/manifest.json",
|
|
356
359
|
sbom: ".aienvmp/sbom.json",
|
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
|
}
|