aienvmp 0.1.61 → 0.1.63
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 +20 -0
- package/README.md +4 -1
- package/package.json +1 -1
- package/src/cli.js +2 -2
- package/src/commands/context.js +1 -0
- package/src/commands/status.js +35 -9
- package/src/commands/summary.js +3 -0
- package/src/contract.js +3 -2
- package/src/preflight.js +53 -0
- package/src/render.js +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.63
|
|
4
|
+
|
|
5
|
+
- Compressed plain `aienvmp status` output into a 5-line AI/human decision view.
|
|
6
|
+
- Added `aienvmp status --verbose` for detailed command hints without cluttering the default path.
|
|
7
|
+
- Added a reusable `renderStatusText` helper for stable status text formatting.
|
|
8
|
+
- Kept JSON/status artifacts unchanged so AI consumers retain the full preflight contract.
|
|
9
|
+
- Updated CLI help to explain the compact default and verbose detail mode.
|
|
10
|
+
- Updated README command guidance for default, artifact, and verbose status usage.
|
|
11
|
+
- Added regression tests for compact default output, verbose output, and exact status text shape.
|
|
12
|
+
|
|
13
|
+
## 0.1.62
|
|
14
|
+
|
|
15
|
+
- Added a compact `collaboration` block to the shared preflight/status contract for multi-agent environment coordination.
|
|
16
|
+
- Exposed `collaboration` at the root of `context --json` so AI agents can read status, active targets, and the next command without digging through multiple sections.
|
|
17
|
+
- Added the collaboration status and rule to `.aienvmp/summary.md`.
|
|
18
|
+
- Added a short collaboration line to plain `aienvmp status` output.
|
|
19
|
+
- Added an `AI Collaboration` dashboard card with status, active targets, env-change rule, and next command.
|
|
20
|
+
- Documented the collaboration block in the stable schema contract and README.
|
|
21
|
+
- Added regression tests for status, context, summary, dashboard, and schema surfaces.
|
|
22
|
+
|
|
3
23
|
## 0.1.61
|
|
4
24
|
|
|
5
25
|
- Added an `aienvmp strict plan` block to the GitHub Action Step Summary.
|
package/README.md
CHANGED
|
@@ -51,6 +51,7 @@ AIENV.md # Markdown env map for AI agents
|
|
|
51
51
|
- `summary.md` is the short CI/AI handoff view, with `AI readiness`, signals, and next action first.
|
|
52
52
|
- `status.json.nextAgent` tells the next AI what to read and whether to review first.
|
|
53
53
|
- `aiReadiness` gives a one-field ready/review signal for AI continuation.
|
|
54
|
+
- `collaboration` gives the shortest multi-agent env-change status, targets, and next command.
|
|
54
55
|
- `dependencyReadSet` lists manifests and lockfiles before package or security changes.
|
|
55
56
|
- `sbomRisk` gives AI a compact light-SBOM risk level, signals, and next command.
|
|
56
57
|
- `sbom.json.aiDependencyReview` connects SBOM risk, scanner confidence, and safe dependency-change steps.
|
|
@@ -81,7 +82,9 @@ Snippets point each AI to `status`, `summary.md`, `context --json`, intent, and
|
|
|
81
82
|
|
|
82
83
|
```bash
|
|
83
84
|
aienvmp sync # update env map, status, summary, SBOM, dashboard
|
|
84
|
-
aienvmp status
|
|
85
|
+
aienvmp status # 5-line env decision
|
|
86
|
+
aienvmp status --write # refresh compact AI status artifact
|
|
87
|
+
aienvmp status --verbose # show command details
|
|
85
88
|
aienvmp summary --write # refresh compact Markdown summary
|
|
86
89
|
aienvmp context --json # AI decision contract
|
|
87
90
|
aienvmp sbom --json # standalone light SBOM
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -112,7 +112,7 @@ function printUsage() {
|
|
|
112
112
|
Usage:
|
|
113
113
|
aienvmp sync [--dir .] [--json] [--quiet] [--deep] [--security]
|
|
114
114
|
aienvmp context [--dir .] [--json]
|
|
115
|
-
aienvmp status [--dir .] [--json] [--write] [--quiet]
|
|
115
|
+
aienvmp status [--dir .] [--json] [--write] [--quiet] [--verbose]
|
|
116
116
|
aienvmp handoff [--dir .] [--json] [--record --actor agent:id]
|
|
117
117
|
aienvmp checkpoint [--dir .] --actor agent:id --summary "what changed" [--target dependency] [--json]
|
|
118
118
|
aienvmp plan [--dir .] [--json] [--write]
|
|
@@ -122,7 +122,7 @@ Usage:
|
|
|
122
122
|
|
|
123
123
|
Common:
|
|
124
124
|
aienvmp sync update AIENV.md, manifest, status, summary, SBOM, ledger, intents, and dashboard
|
|
125
|
-
aienvmp status print
|
|
125
|
+
aienvmp status print a 5-line AI/human environment decision; --verbose shows command details
|
|
126
126
|
aienvmp context print the AI preflight brief
|
|
127
127
|
aienvmp handoff print the next-agent handoff summary
|
|
128
128
|
aienvmp checkpoint record, sync, status, and handoff after an env change
|
package/src/commands/context.js
CHANGED
|
@@ -27,6 +27,7 @@ export async function contextWorkspace(args) {
|
|
|
27
27
|
status: warnings.length ? "review-required" : "clear",
|
|
28
28
|
preflight,
|
|
29
29
|
aiReadiness: preflight.aiReadiness,
|
|
30
|
+
collaboration: preflight.collaboration,
|
|
30
31
|
coordination: preflight.coordination,
|
|
31
32
|
agentPointers: preflight.agentPointers,
|
|
32
33
|
sbomRisk: preflight.sbomRisk,
|
package/src/commands/status.js
CHANGED
|
@@ -21,15 +21,7 @@ export async function statusWorkspace(args) {
|
|
|
21
21
|
if (args.json) {
|
|
22
22
|
console.log(JSON.stringify(output, null, 2));
|
|
23
23
|
} else if (!args.quiet) {
|
|
24
|
-
console.log(
|
|
25
|
-
console.log(`ai-readiness: ${output.aiReadiness?.level || "unknown"} - ${output.aiReadiness?.next || "Run aienvmp context --json for details."}`);
|
|
26
|
-
console.log(`next: ${output.nextCommand}`);
|
|
27
|
-
console.log(`ai: ${output.quickstart.readFirst} -> ${output.quickstart.detailCommand}`);
|
|
28
|
-
console.log(`intent: ${output.intentTargets[0]?.command || output.commands.recordIntent}`);
|
|
29
|
-
console.log(`checkpoint: ${output.commands.checkpoint}`);
|
|
30
|
-
console.log(`handoff: ${output.nextAgent.handoffCommand}`);
|
|
31
|
-
console.log(`strict: ${output.enforcement.recommendedCommand}`);
|
|
32
|
-
if (artifact) console.log(`status: ${artifact}`);
|
|
24
|
+
console.log(renderStatusText(output, { verbose: args.verbose === true, artifact }));
|
|
33
25
|
}
|
|
34
26
|
return output;
|
|
35
27
|
}
|
|
@@ -44,3 +36,37 @@ export async function writeStatusArtifact(dir, status) {
|
|
|
44
36
|
export function buildStatus(manifest = {}, warnings = [], intents = [], timeline = []) {
|
|
45
37
|
return buildPreflight(manifest, warnings, intents, timeline);
|
|
46
38
|
}
|
|
39
|
+
|
|
40
|
+
export function renderStatusText(output = {}, options = {}) {
|
|
41
|
+
const counts = output.counts || {};
|
|
42
|
+
const readiness = output.aiReadiness?.level || "unknown";
|
|
43
|
+
const collaboration = output.collaboration?.status || "unknown";
|
|
44
|
+
const sbomRisk = output.sbomRisk?.level || "unknown";
|
|
45
|
+
const sbomScore = valueOrZero(output.sbomRisk?.score);
|
|
46
|
+
const detail = output.quickstart?.detailCommand || "aienvmp context --json";
|
|
47
|
+
const summary = output.artifacts?.summary || ".aienvmp/summary.md";
|
|
48
|
+
const lines = [
|
|
49
|
+
`${output.state || "unknown"}: ${output.summary || "Run aienvmp context --json for details."}`,
|
|
50
|
+
`ready: ${readiness} | collaboration: ${collaboration}`,
|
|
51
|
+
`sbom: ${sbomRisk} (${sbomScore}) | warnings: ${valueOrZero(counts.warnings)} | intents: ${valueOrZero(counts.openIntents)}`,
|
|
52
|
+
`next: ${output.nextCommand || "aienvmp status --json"}`,
|
|
53
|
+
`details: ${detail} | summary: ${summary}`
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
if (options.verbose) {
|
|
57
|
+
lines.push(
|
|
58
|
+
`ai: ${output.quickstart?.readFirst || "aienvmp status --write"} -> ${detail}`,
|
|
59
|
+
`intent: ${output.intentTargets?.[0]?.command || output.commands?.recordIntent || "aienvmp intent --actor agent:id --action planned-change"}`,
|
|
60
|
+
`checkpoint: ${output.commands?.checkpoint || "aienvmp checkpoint --actor agent:id --summary what-changed --target environment"}`,
|
|
61
|
+
`handoff: ${output.nextAgent?.handoffCommand || "aienvmp handoff --record --actor agent:id"}`,
|
|
62
|
+
`strict: ${output.enforcement?.recommendedCommand || "aienvmp doctor --strict all"}`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (options.artifact || output.artifact) lines.push(`status: ${options.artifact || output.artifact}`);
|
|
67
|
+
return lines.join("\n");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function valueOrZero(value) {
|
|
71
|
+
return Number.isFinite(Number(value)) ? Number(value) : 0;
|
|
72
|
+
}
|
package/src/commands/summary.js
CHANGED
|
@@ -37,6 +37,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
37
37
|
const sbomRisk = status.sbomRisk || manifest.lightSbom?.riskSummary || {};
|
|
38
38
|
const coordination = status.coordination || {};
|
|
39
39
|
const activity = status.agentActivity || {};
|
|
40
|
+
const collaboration = status.collaboration || {};
|
|
40
41
|
const workspace = manifest.workspace?.root || manifest.workspace?.name || ".";
|
|
41
42
|
const next = status.nextCommand || status.decision?.nextCommand || "aienvmp status";
|
|
42
43
|
const readFirst = status.nextAgent?.readFirst || ".aienvmp/status.json";
|
|
@@ -64,6 +65,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
64
65
|
`- AI readiness: ${aiReadiness.level || "unknown"}`,
|
|
65
66
|
`- AI signals: ${aiSignals.length ? aiSignals.join("; ") : "none"}`,
|
|
66
67
|
`- AI next: ${aiNext}`,
|
|
68
|
+
`- AI collaboration: ${collaboration.status || "unknown"} / ${toList(collaboration.activeTargets).join(", ") || "none"} / ${collaboration.nextCommand || "aienvmp status --json"}`,
|
|
67
69
|
`- AI safe local work: ${toList(aiReadiness.safeProjectLocalActions)[0] || "read artifacts and avoid environment changes until reviewed"}`,
|
|
68
70
|
`- AI read first: ${readFirst}, then ${detail}`,
|
|
69
71
|
`- mode: advisory by default; strict is opt-in with ${strict}`,
|
|
@@ -79,6 +81,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
79
81
|
"## AI handoff",
|
|
80
82
|
"",
|
|
81
83
|
`- environment changes: ${status.agentUse?.environmentChanges || "intent-and-review-first"}`,
|
|
84
|
+
`- collaboration rule: ${collaboration.rule || "Record intent before shared environment changes."}`,
|
|
82
85
|
`- coordination: ${coordination.next || "No open environment intents."}`,
|
|
83
86
|
`- recent agent activity: ${activity.next || "No environment records need coordination."}`,
|
|
84
87
|
`- conflict targets: ${conflictTargets.length ? conflictTargets.join(", ") : "none"}`,
|
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", "aiReadiness", "nextAgent", "coordination", "agentActivity", "agentPointers", "sbomRisk", "followUps", "dependencyReadSet", "dependencyChangeProtocol"],
|
|
7
|
+
aiEntryFields: ["state", "summary", "aiReadiness", "collaboration", "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
|
}
|
|
@@ -29,7 +29,7 @@ export function schemaContract() {
|
|
|
29
29
|
},
|
|
30
30
|
context: {
|
|
31
31
|
command: "aienvmp context --json",
|
|
32
|
-
rootFields: ["status", "preflight", "aiReadiness", "coordination", "agentPointers", "decision", "enforcement", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
32
|
+
rootFields: ["status", "preflight", "aiReadiness", "collaboration", "coordination", "agentPointers", "decision", "enforcement", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
33
33
|
},
|
|
34
34
|
handoff: {
|
|
35
35
|
command: "aienvmp handoff --json",
|
|
@@ -56,6 +56,7 @@ export function schemaContract() {
|
|
|
56
56
|
consumerRule: "Ignore unknown fields. Do not require optional fields unless listed in requiredFields.",
|
|
57
57
|
localBehavior: "read-only; this command does not scan, install, update, or lock anything.",
|
|
58
58
|
aiReadinessRule: "When aiReadiness.level is review, project-local code work may still continue if aiReadiness.projectLocalWork is allowed; environment changes should follow intent/review guidance.",
|
|
59
|
+
collaborationRule: "Use collaboration.status, activeTargets, and nextCommand as the shortest multi-agent environment coordination hint.",
|
|
59
60
|
strictPlanRule: "Use enforcement.strictPlan or preflight.enforcementProfile.strictPlan to choose the narrowest explicit strict scope for CI."
|
|
60
61
|
}
|
|
61
62
|
};
|
package/src/preflight.js
CHANGED
|
@@ -19,6 +19,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
19
19
|
const sbomRisk = manifest.lightSbom?.riskSummary || {};
|
|
20
20
|
const agentPointers = agentPointerSummary(manifest.agentFiles);
|
|
21
21
|
const aiReadiness = aiReadinessSummary({ state, decision, coordination, agentActivity, agentPointers, sbomRisk, followUps });
|
|
22
|
+
const collaboration = collaborationSummary({ state, decision, coordination, agentActivity, followUps, aiReadiness });
|
|
22
23
|
return {
|
|
23
24
|
schemaVersion: 1,
|
|
24
25
|
contract: preflightContract(),
|
|
@@ -61,6 +62,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
61
62
|
nextAgent: nextAgentHint(state, dependencyReadSet, dependencyChangeProtocol),
|
|
62
63
|
coordination,
|
|
63
64
|
agentActivity,
|
|
65
|
+
collaboration,
|
|
64
66
|
agentPointers,
|
|
65
67
|
aiReadiness,
|
|
66
68
|
sbomRisk,
|
|
@@ -92,6 +94,45 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
92
94
|
};
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
function collaborationSummary({ state, decision, coordination, agentActivity, followUps, aiReadiness }) {
|
|
98
|
+
const conflictTargets = coordination?.conflictTargets || [];
|
|
99
|
+
const multiActorTargets = agentActivity?.multiActorTargets || [];
|
|
100
|
+
const followUpTargets = (followUps || []).map((item) => item.target || "environment");
|
|
101
|
+
const activeTargets = unique([...conflictTargets, ...multiActorTargets, ...followUpTargets]);
|
|
102
|
+
const reviewSignals = [];
|
|
103
|
+
if (conflictTargets.length) reviewSignals.push("open intent conflict");
|
|
104
|
+
if (multiActorTargets.length) reviewSignals.push("multi-agent environment record");
|
|
105
|
+
if ((followUps || []).length) reviewSignals.push("pending post-change follow-up");
|
|
106
|
+
if (state !== "clear") reviewSignals.push("preflight review required");
|
|
107
|
+
|
|
108
|
+
const nextCommand = firstFollowUpCommand(followUps)
|
|
109
|
+
|| (multiActorTargets.length ? "aienvmp handoff --record --actor agent:id" : "")
|
|
110
|
+
|| (conflictTargets.length ? "aienvmp plan --write" : "")
|
|
111
|
+
|| (decision?.canChangeEnvironmentWithoutReview
|
|
112
|
+
? "aienvmp intent --actor agent:id --action planned-change --target environment"
|
|
113
|
+
: "aienvmp context --json");
|
|
114
|
+
|
|
115
|
+
const status = reviewSignals.length ? "review-before-env-change" : "clear";
|
|
116
|
+
return {
|
|
117
|
+
status,
|
|
118
|
+
mode: "advisory",
|
|
119
|
+
activeTargets,
|
|
120
|
+
reviewSignals,
|
|
121
|
+
projectLocalWork: aiReadiness?.projectLocalWork || (decision?.canContinueProjectLocalWork ? "allowed" : "review-first"),
|
|
122
|
+
environmentChanges: reviewSignals.length ? "intent-review-handoff-first" : "intent-first",
|
|
123
|
+
nextCommand,
|
|
124
|
+
rule: reviewSignals.length
|
|
125
|
+
? "Do not install, remove, upgrade, downgrade, or switch shared environment tools until the listed collaboration signals are reviewed."
|
|
126
|
+
: "Multiple AI agents may continue project-local work; record intent before shared environment changes.",
|
|
127
|
+
commands: {
|
|
128
|
+
read: "aienvmp status --json",
|
|
129
|
+
plan: "aienvmp plan --write",
|
|
130
|
+
handoff: "aienvmp handoff --record --actor agent:id",
|
|
131
|
+
checkpoint: "aienvmp checkpoint --actor agent:id --summary what-changed --target environment"
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
95
136
|
function aiReadinessSummary({ state, decision, coordination, agentActivity, agentPointers, sbomRisk, followUps }) {
|
|
96
137
|
const blockers = [];
|
|
97
138
|
const review = [];
|
|
@@ -429,6 +470,18 @@ function normalizeTarget(target = "") {
|
|
|
429
470
|
return normalized;
|
|
430
471
|
}
|
|
431
472
|
|
|
473
|
+
function unique(items = []) {
|
|
474
|
+
return [...new Set(items.map((item) => normalizeTarget(item)).filter(Boolean))];
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function firstFollowUpCommand(followUps = []) {
|
|
478
|
+
for (const item of followUps || []) {
|
|
479
|
+
const command = item.commands?.find(Boolean);
|
|
480
|
+
if (command) return command;
|
|
481
|
+
}
|
|
482
|
+
return "";
|
|
483
|
+
}
|
|
484
|
+
|
|
432
485
|
function agentQuickstart(reviewRequired) {
|
|
433
486
|
return {
|
|
434
487
|
label: "10-second AI flow",
|
package/src/render.js
CHANGED
|
@@ -484,6 +484,8 @@ const followUpsHtml=followUps.length?'<div class="timeline">'+followUps.slice(0,
|
|
|
484
484
|
const agentActivity=manifest.preflight?.agentActivity||{};
|
|
485
485
|
const activityTargets=agentActivity.targets||[];
|
|
486
486
|
const activityHtml=activityTargets.length?'<div class="timeline">'+activityTargets.slice(0,5).map(a=>\`<div class="event"><time>\${esc(a.target||'env')}</time><div><b>\${esc((a.actors||[]).join(', ')||'unknown')}</b> \${esc(a.count||0)} record(s) \${a.multiActor?'<code>multi-agent</code>':'<code>single-agent</code>'}\${a.latestSummary?\`<div class="path">\${esc(a.latestSummary)}</div>\`:''}</div></div>\`).join('')+'</div><div class="path">'+esc(agentActivity.next||'Review activity before environment changes.')+'</div>':'<div class="okline">No recorded environment activity needs coordination.</div>';
|
|
487
|
+
const collaboration=manifest.preflight?.collaboration||{};
|
|
488
|
+
const collaborationHtml=\`<table><tr><th>Status</th><td><code>\${esc(collaboration.status||'unknown')}</code> \${esc(collaboration.mode||'advisory')}</td></tr><tr><th>Targets</th><td>\${esc((collaboration.activeTargets||[]).join(', ')||'none')}</td></tr><tr><th>Project work</th><td><code>\${esc(collaboration.projectLocalWork||'allowed')}</code></td></tr><tr><th>Env changes</th><td><code>\${esc(collaboration.environmentChanges||'intent-first')}</code></td></tr><tr><th>Next</th><td><code>\${esc(collaboration.nextCommand||'aienvmp status --json')}</code></td></tr></table><div class="timeline">\${(collaboration.reviewSignals||[]).slice(0,4).map(signal=>\`<div class="event"><time>review</time><div>\${esc(signal)}</div></div>\`).join('')}</div><div class="path">\${esc(collaboration.rule||'Record intent before shared environment changes.')}</div>\`;
|
|
487
489
|
const dependencyReadSet=manifest.preflight?.dependencyReadSet||[];
|
|
488
490
|
const dependencyReadSetHtml=dependencyReadSet.length?'<div class="timeline">'+dependencyReadSet.slice(0,5).map(d=>\`<div class="event"><time>\${esc(d.ecosystem||'deps')}</time><div><b>\${esc(d.manifest||'dependency files')}</b> <code>\${esc(d.manager||'unknown')}</code><div class="path">\${esc([d.manifest,...(d.lockfiles||[])].filter(Boolean).join(', '))}</div>\${d.riskPackages?.length?\`<div class="path">risk: \${esc(d.riskPackages.join(', '))}</div>\`:''}</div></div>\`).join('')+'</div>':'<div class="okline">No dependency files detected.</div>';
|
|
489
491
|
const dependencyProtocol=manifest.preflight?.dependencyChangeProtocol||{};
|
|
@@ -546,6 +548,8 @@ document.getElementById('app').innerHTML=\`
|
|
|
546
548
|
<div style="height:14px"></div>
|
|
547
549
|
\${card('Agent Activity',agentActivity.multiActorTargets?.length?'<span class="pill warn">'+agentActivity.multiActorTargets.length+' shared</span>':'<span class="pill">clear</span>',activityHtml)}
|
|
548
550
|
<div style="height:14px"></div>
|
|
551
|
+
\${card('AI Collaboration',collaboration.status==='clear'?'<span class="pill">clear</span>':'<span class="pill warn">review</span>',collaborationHtml)}
|
|
552
|
+
<div style="height:14px"></div>
|
|
549
553
|
\${card('AI Contract','<span class="pill">'+(contract.stability||'additive')+'</span>',contractHtml)}
|
|
550
554
|
<div style="height:14px"></div>
|
|
551
555
|
\${card('Dependency Read Set','<span class="pill">'+dependencyReadSet.length+' files</span>',dependencyReadSetHtml)}
|