aienvmp 0.1.3 → 0.1.4
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 +6 -0
- package/README.md +1 -0
- package/package.json +1 -1
- package/src/cli.js +5 -1
- package/src/commands/handoff.js +55 -0
- package/src/render.js +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
- Added `aienvmp handoff` for next-agent environment handoff summaries.
|
|
6
|
+
- Added an AI Handoff card to the dashboard.
|
|
7
|
+
- Added handoff test coverage.
|
|
8
|
+
|
|
3
9
|
## 0.1.3
|
|
4
10
|
|
|
5
11
|
- Strengthened the dashboard audit summary with AI decision, open intents, warnings, and recent changes.
|
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ npx aienvmp snippet agents
|
|
|
48
48
|
aienvmp sync # update env map, light SBOM, ledger, dashboard
|
|
49
49
|
aienvmp context # AI preflight brief
|
|
50
50
|
aienvmp context --json # machine-readable AI decision context
|
|
51
|
+
aienvmp handoff # next-agent handoff summary
|
|
51
52
|
aienvmp intent # record a planned env change
|
|
52
53
|
aienvmp record # record what changed
|
|
53
54
|
aienvmp doctor --ci # strict CI check
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { intentWorkspace } from "./commands/intent.js";
|
|
|
10
10
|
import { resolveWorkspace } from "./commands/resolve.js";
|
|
11
11
|
import { syncWorkspace } from "./commands/sync.js";
|
|
12
12
|
import { snippetWorkspace } from "./commands/snippet.js";
|
|
13
|
+
import { handoffWorkspace } from "./commands/handoff.js";
|
|
13
14
|
import { readFileSync } from "node:fs";
|
|
14
15
|
|
|
15
16
|
const commands = new Map([
|
|
@@ -24,7 +25,8 @@ const commands = new Map([
|
|
|
24
25
|
["intent", intentWorkspace],
|
|
25
26
|
["resolve", resolveWorkspace],
|
|
26
27
|
["sync", syncWorkspace],
|
|
27
|
-
["snippet", snippetWorkspace]
|
|
28
|
+
["snippet", snippetWorkspace],
|
|
29
|
+
["handoff", handoffWorkspace]
|
|
28
30
|
]);
|
|
29
31
|
|
|
30
32
|
const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
@@ -74,10 +76,12 @@ function printUsage() {
|
|
|
74
76
|
Usage:
|
|
75
77
|
aienvmp sync [--dir .] [--json] [--quiet]
|
|
76
78
|
aienvmp context [--dir .] [--json]
|
|
79
|
+
aienvmp handoff [--dir .] [--json]
|
|
77
80
|
|
|
78
81
|
Common:
|
|
79
82
|
aienvmp sync update AIENV.md, manifest, ledger, intents, and dashboard
|
|
80
83
|
aienvmp context print the AI preflight brief
|
|
84
|
+
aienvmp handoff print the next-agent handoff summary
|
|
81
85
|
aienvmp snippet print an AGENTS.md pointer snippet
|
|
82
86
|
aienvmp dash regenerate/open the lightweight dashboard
|
|
83
87
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { diagnose } from "../doctor.js";
|
|
2
|
+
import { readJson } from "../fsutil.js";
|
|
3
|
+
import { loadPolicy, policyWarnings } from "../policy.js";
|
|
4
|
+
import { intentsPath, manifestPath, timelinePath, workspaceDir } from "../paths.js";
|
|
5
|
+
import { renderHandoff } from "../render.js";
|
|
6
|
+
import { openIntents, readJsonl, readTimeline } from "../timeline.js";
|
|
7
|
+
|
|
8
|
+
export async function handoffWorkspace(args) {
|
|
9
|
+
const dir = workspaceDir(args);
|
|
10
|
+
const manifest = await readJson(manifestPath(dir));
|
|
11
|
+
if (!manifest) throw new Error("missing manifest; run `aienvmp sync` first");
|
|
12
|
+
const timeline = await readTimeline(timelinePath(dir));
|
|
13
|
+
const intents = openIntents(await readJsonl(intentsPath(dir)));
|
|
14
|
+
const policy = await loadPolicy(dir);
|
|
15
|
+
const warnings = [...diagnose(manifest), ...policyWarnings(manifest, policy)];
|
|
16
|
+
const handoff = buildHandoff(manifest, timeline, warnings, intents, policy);
|
|
17
|
+
|
|
18
|
+
if (args.json) {
|
|
19
|
+
console.log(JSON.stringify(handoff, null, 2));
|
|
20
|
+
} else {
|
|
21
|
+
console.log(renderHandoff(handoff));
|
|
22
|
+
}
|
|
23
|
+
return handoff;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function buildHandoff(manifest, timeline = [], warnings = [], intents = [], policy = {}) {
|
|
27
|
+
const reviewRequired = warnings.length > 0 || intents.length > 0;
|
|
28
|
+
return {
|
|
29
|
+
status: reviewRequired ? "review-required" : "clear",
|
|
30
|
+
workspace: manifest.workspace,
|
|
31
|
+
safeRuntime: {
|
|
32
|
+
node: manifest.runtimes?.node || "not detected",
|
|
33
|
+
python: manifest.runtimes?.python || manifest.runtimes?.python3 || "not detected",
|
|
34
|
+
docker: manifest.containers?.docker ? "available" : "not detected"
|
|
35
|
+
},
|
|
36
|
+
policy: {
|
|
37
|
+
node: policy.node || "not set",
|
|
38
|
+
python: policy.python || "not set",
|
|
39
|
+
packageManager: policy.packageManager || "not set",
|
|
40
|
+
runtimeChanges: policy.runtimeChanges || "ask-first",
|
|
41
|
+
globalInstalls: policy.globalInstalls || "ask-first"
|
|
42
|
+
},
|
|
43
|
+
openIntents: intents.slice(-5).reverse(),
|
|
44
|
+
warnings,
|
|
45
|
+
recentChanges: timeline.slice(-5).reverse(),
|
|
46
|
+
mustNotDo: [
|
|
47
|
+
"do not change global runtimes without user approval",
|
|
48
|
+
"do not install or remove global package managers without user approval",
|
|
49
|
+
"do not change Docker daemon/context assumptions without user approval"
|
|
50
|
+
],
|
|
51
|
+
recommendedNext: reviewRequired
|
|
52
|
+
? "review warnings and open intents before environment changes"
|
|
53
|
+
: "continue with project-local work; record intent before environment changes"
|
|
54
|
+
};
|
|
55
|
+
}
|
package/src/render.js
CHANGED
|
@@ -111,6 +111,36 @@ export function renderContext(manifest, timeline = [], warnings = [], intents =
|
|
|
111
111
|
].join("\n");
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
export function renderHandoff(handoff) {
|
|
115
|
+
const lines = [
|
|
116
|
+
"# AI Handoff",
|
|
117
|
+
"",
|
|
118
|
+
`Status: ${handoff.status}`,
|
|
119
|
+
`Workspace: ${handoff.workspace?.path || "unknown"}`,
|
|
120
|
+
"",
|
|
121
|
+
"Safe runtime:",
|
|
122
|
+
`- Node: ${handoff.safeRuntime.node}`,
|
|
123
|
+
`- Python: ${handoff.safeRuntime.python}`,
|
|
124
|
+
`- Docker: ${handoff.safeRuntime.docker}`,
|
|
125
|
+
"",
|
|
126
|
+
"Open intents:",
|
|
127
|
+
...(handoff.openIntents.length ? handoff.openIntents.map((i) => `- ${i.actor}: ${i.action}${i.target ? ` (${i.target})` : ""}`) : ["- none"]),
|
|
128
|
+
"",
|
|
129
|
+
"Warnings:",
|
|
130
|
+
...(handoff.warnings.length ? handoff.warnings.map((w) => `- ${w.message}`) : ["- none"]),
|
|
131
|
+
"",
|
|
132
|
+
"Recent changes:",
|
|
133
|
+
...(handoff.recentChanges.length ? handoff.recentChanges.map((t) => `- ${formatTimeline(t)}`) : ["- none"]),
|
|
134
|
+
"",
|
|
135
|
+
"Must not do:",
|
|
136
|
+
...handoff.mustNotDo.map((item) => `- ${item}`),
|
|
137
|
+
"",
|
|
138
|
+
`Recommended next: ${handoff.recommendedNext}`,
|
|
139
|
+
""
|
|
140
|
+
];
|
|
141
|
+
return lines.join("\n");
|
|
142
|
+
}
|
|
143
|
+
|
|
114
144
|
export function renderDashboard(manifest, timeline = [], warnings = [], intents = [], policy = {}) {
|
|
115
145
|
const data = JSON.stringify({ manifest, timeline, warnings, intents, policy });
|
|
116
146
|
return `<!doctype html>
|
|
@@ -180,6 +210,7 @@ const reviewRequired=warnings.length>0||intents.length>0;
|
|
|
180
210
|
const recentChanges=timeline.slice(-8).length;
|
|
181
211
|
const nextAction=reviewRequired?'Review before environment changes':'Proceed with project-local work';
|
|
182
212
|
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>\`;
|
|
213
|
+
const handoffHtml=\`<table><tr><th>Status</th><td>\${reviewRequired?'review-required':'clear'}</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>\`;
|
|
183
214
|
document.getElementById('app').innerHTML=\`
|
|
184
215
|
<header>
|
|
185
216
|
<div>
|
|
@@ -215,6 +246,8 @@ document.getElementById('app').innerHTML=\`
|
|
|
215
246
|
<div style="height:14px"></div>
|
|
216
247
|
\${card('Agent Intents','<span class="pill">'+intents.length+' open</span>',intentsHtml)}
|
|
217
248
|
<div style="height:14px"></div>
|
|
249
|
+
\${card('AI Handoff',reviewRequired?'<span class="pill warn">review</span>':'<span class="pill">ready</span>',handoffHtml)}
|
|
250
|
+
<div style="height:14px"></div>
|
|
218
251
|
\${card('Agent Pointers','<span class="pill">'+entries(manifest.agentFiles).filter(([,v])=>v).length+' detected</span>','<div class="agents">'+agentCards+'</div>')}
|
|
219
252
|
<div style="height:14px"></div>
|
|
220
253
|
\${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>\`)}
|