aienvmp 0.1.2 → 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/BUGFIXES.md +38 -0
- package/CHANGELOG.md +12 -0
- package/README.md +2 -1
- package/TROUBLESHOOTING.md +103 -0
- package/package.json +3 -1
- package/src/cli.js +5 -1
- package/src/commands/handoff.js +55 -0
- package/src/render.js +52 -0
package/BUGFIXES.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Bugfix Log
|
|
2
|
+
|
|
3
|
+
Short record of bugs, fixes, and follow-up checks.
|
|
4
|
+
|
|
5
|
+
## 2026-07-08
|
|
6
|
+
|
|
7
|
+
### CLI version was hardcoded
|
|
8
|
+
|
|
9
|
+
- Issue: `npm run smoke` printed `0.1.0` after the package version changed.
|
|
10
|
+
- Fix: CLI now reads the version from `package.json`.
|
|
11
|
+
- Verification: `npm run smoke` prints the package version.
|
|
12
|
+
|
|
13
|
+
### AGENTS.md default generation conflicted with product focus
|
|
14
|
+
|
|
15
|
+
- Issue: default agent instruction file generation made `aienvmp` look like an AGENTS.md generator.
|
|
16
|
+
- Fix: `sync` now focuses on `AIENV.md`, manifest, intent log, timeline, and dashboard. Agent instruction integration is explicit through `aienvmp snippet`.
|
|
17
|
+
- Verification: `node --test` confirms `sync` does not create `AGENTS.md` by default and `snippet --write` only updates the marker block.
|
|
18
|
+
|
|
19
|
+
### npm publish metadata appeared stale
|
|
20
|
+
|
|
21
|
+
- Issue: npm publish returned success for `0.1.2`, but `npm view aienvmp version` briefly returned `0.1.1`.
|
|
22
|
+
- Fix: verified with `npm view aienvmp versions --json` and `npm dist-tag ls aienvmp`; registry later reported `0.1.2`.
|
|
23
|
+
- Verification: `npm view aienvmp version` returns `0.1.2`.
|
|
24
|
+
|
|
25
|
+
### macOS SSH PATH did not expose Node/npm
|
|
26
|
+
|
|
27
|
+
- Issue: remote macOS non-interactive SSH command did not find `node` or `npm`.
|
|
28
|
+
- Fix: test command used `/bin/zsh -lc` to load login shell PATH.
|
|
29
|
+
- Verification: remote test detected Node `v25.3.0`, npm `11.11.0`, and completed `aienvmp sync`.
|
|
30
|
+
|
|
31
|
+
## Template
|
|
32
|
+
|
|
33
|
+
### Title
|
|
34
|
+
|
|
35
|
+
- Issue:
|
|
36
|
+
- Fix:
|
|
37
|
+
- Verification:
|
|
38
|
+
- Follow-up:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
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
|
+
|
|
9
|
+
## 0.1.3
|
|
10
|
+
|
|
11
|
+
- Strengthened the dashboard audit summary with AI decision, open intents, warnings, and recent changes.
|
|
12
|
+
- Added dashboard render coverage for the audit summary surface.
|
|
13
|
+
|
|
3
14
|
## 0.1.2
|
|
4
15
|
|
|
5
16
|
- Added `aienvmp sync` as the simple one-step command for init, scan, `AIENV.md`, manifest, ledger, and dashboard generation.
|
|
@@ -8,6 +19,7 @@
|
|
|
8
19
|
- Added machine-readable sync/context improvements for AI and CI integrations.
|
|
9
20
|
- Simplified README for faster first-time understanding.
|
|
10
21
|
- Kept AGENTS.md, CLAUDE.md, and GEMINI.md integration explicit through `aienvmp snippet`.
|
|
22
|
+
- Added troubleshooting and bugfix logs for operational issue tracking.
|
|
11
23
|
|
|
12
24
|
## 0.1.1
|
|
13
25
|
|
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
|
|
@@ -70,6 +71,6 @@ npm pack --dry-run
|
|
|
70
71
|
|
|
71
72
|
## Links
|
|
72
73
|
|
|
73
|
-
[Roadmap](ROADMAP.md) / [Security](SECURITY.md) / [Contributing](CONTRIBUTING.md)
|
|
74
|
+
[Roadmap](ROADMAP.md) / [Security](SECURITY.md) / [Troubleshooting](TROUBLESHOOTING.md) / [Bugfix Log](BUGFIXES.md) / [Contributing](CONTRIBUTING.md)
|
|
74
75
|
|
|
75
76
|
Apache-2.0
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Known operational issues and quick fixes for `aienvmp`.
|
|
4
|
+
|
|
5
|
+
## npm publish succeeds but `npm view` still shows the old version
|
|
6
|
+
|
|
7
|
+
Symptom:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
npm publish
|
|
11
|
+
+ aienvmp@0.1.2
|
|
12
|
+
npm view aienvmp version
|
|
13
|
+
0.1.1
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Cause:
|
|
17
|
+
|
|
18
|
+
- npm registry metadata can lag briefly after publish.
|
|
19
|
+
|
|
20
|
+
Check:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm view aienvmp versions --json
|
|
24
|
+
npm dist-tag ls aienvmp
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Fix:
|
|
28
|
+
|
|
29
|
+
- Wait briefly and re-check `npm view aienvmp version`.
|
|
30
|
+
|
|
31
|
+
## Windows `npm exec --package ... -- aienvmp --help` cannot find the command
|
|
32
|
+
|
|
33
|
+
Symptom:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
'aienvmp' is not recognized as an internal or external command
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Notes:
|
|
40
|
+
|
|
41
|
+
- The package bin metadata can still be valid.
|
|
42
|
+
- A direct temporary install creates the expected `.bin/aienvmp.cmd` shim.
|
|
43
|
+
|
|
44
|
+
Check:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm view aienvmp bin --json
|
|
48
|
+
npm install aienvmp@latest --prefix ./tmp-aienvmp-check
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Workaround:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx aienvmp@latest --version
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
or install first:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install -g aienvmp
|
|
61
|
+
aienvmp --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## macOS SSH session cannot find `node` or `npm`
|
|
65
|
+
|
|
66
|
+
Symptom:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
command -v node
|
|
70
|
+
# empty in non-interactive SSH command
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Cause:
|
|
74
|
+
|
|
75
|
+
- Node may be configured only in the login shell environment.
|
|
76
|
+
|
|
77
|
+
Fix:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
/bin/zsh -lc 'node --version && npm --version'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
For automation, make sure the shell PATH includes the Node/npm location.
|
|
84
|
+
|
|
85
|
+
## Missing manifest
|
|
86
|
+
|
|
87
|
+
Symptom:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
aienvmp: missing manifest; run `aienvmp sync` first
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Fix:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx aienvmp sync
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then retry:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx aienvmp context
|
|
103
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aienvmp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "AI-first environment maps and lightweight runtime SBOMs for shared development machines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,8 +20,10 @@
|
|
|
20
20
|
"README.md",
|
|
21
21
|
"LICENSE",
|
|
22
22
|
"CHANGELOG.md",
|
|
23
|
+
"BUGFIXES.md",
|
|
23
24
|
"CONTRIBUTING.md",
|
|
24
25
|
"SECURITY.md",
|
|
26
|
+
"TROUBLESHOOTING.md",
|
|
25
27
|
"ROADMAP.md",
|
|
26
28
|
"action.yml",
|
|
27
29
|
"examples",
|
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>
|
|
@@ -131,6 +161,13 @@ h1,h2,h3,p{margin:0}h1{font-size:clamp(28px,4vw,46px);line-height:1.02;margin-to
|
|
|
131
161
|
.sub{color:var(--muted);margin-top:12px;max-width:680px;line-height:1.55}
|
|
132
162
|
.stamp{min-width:220px;border:1px solid var(--line2);background:#091310;border-radius:8px;padding:14px}
|
|
133
163
|
.stamp b{display:block;color:var(--green);font-size:24px;margin-bottom:3px}.stamp span{display:block;color:var(--muted);font-size:12px;overflow-wrap:anywhere}
|
|
164
|
+
.audit{display:grid;grid-template-columns:1.2fr repeat(3,minmax(0,.8fr));gap:12px;margin:14px 0}
|
|
165
|
+
.audit-item{border:1px solid var(--line);background:rgba(13,24,21,.92);border-radius:8px;padding:14px;min-width:0}
|
|
166
|
+
.audit-item.primary{background:linear-gradient(135deg,rgba(19,61,42,.88),rgba(9,19,16,.95))}
|
|
167
|
+
.audit-item.review{background:linear-gradient(135deg,rgba(81,53,17,.88),rgba(9,19,16,.95));border-color:rgba(244,191,95,.42)}
|
|
168
|
+
.audit-k{color:var(--muted);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.08em}
|
|
169
|
+
.audit-v{margin-top:7px;font-size:20px;font-weight:800;color:var(--text);overflow-wrap:anywhere}
|
|
170
|
+
.audit-hint{margin-top:6px;color:var(--muted);font-size:12px;line-height:1.4}
|
|
134
171
|
.metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin:14px 0 18px}
|
|
135
172
|
.metric,.card{border:1px solid var(--line);background:rgba(13,24,21,.9);border-radius:8px}
|
|
136
173
|
.metric{padding:14px}.metric .num{font-size:28px;font-weight:800;color:var(--green);line-height:1}.metric .label{margin-top:7px;color:var(--muted);font-size:12px}
|
|
@@ -147,7 +184,9 @@ code{color:var(--code);background:#0a2017;border:1px solid #17462f;padding:2px 6
|
|
|
147
184
|
.timeline{display:grid;gap:10px}.event{display:grid;grid-template-columns:108px 1fr;gap:12px;border-top:1px solid var(--line2);padding-top:10px}.event time{color:var(--muted);font-size:12px}.event b{color:var(--green)}
|
|
148
185
|
.path{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--muted);font-size:12px;overflow-wrap:anywhere}
|
|
149
186
|
@media (max-width:860px){header,.layout{grid-template-columns:1fr}.metrics{grid-template-columns:repeat(2,1fr)}.grid{grid-template-columns:1fr}.agents{grid-template-columns:1fr}}
|
|
187
|
+
@media (max-width:860px){.audit{grid-template-columns:1fr 1fr}}
|
|
150
188
|
@media (max-width:520px){.shell{padding:14px}.metrics{grid-template-columns:1fr}.event{grid-template-columns:1fr}h1{font-size:32px}}
|
|
189
|
+
@media (max-width:520px){.audit{grid-template-columns:1fr}}
|
|
151
190
|
</style>
|
|
152
191
|
</head>
|
|
153
192
|
<body>
|
|
@@ -167,6 +206,11 @@ const timelineHtml=timeline.length?'<div class="timeline">'+timeline.slice(-8).r
|
|
|
167
206
|
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>';
|
|
168
207
|
const policyHtml=entries(policy).length?\`<table>\${rows(policy)}</table>\`:'<div class="okline">No explicit version policy set.</div>';
|
|
169
208
|
const card=(title,badge,body)=>\`<section class="card"><div class="card-head"><h2>\${title}</h2>\${badge||''}</div>\${body}</section>\`;
|
|
209
|
+
const reviewRequired=warnings.length>0||intents.length>0;
|
|
210
|
+
const recentChanges=timeline.slice(-8).length;
|
|
211
|
+
const nextAction=reviewRequired?'Review before environment changes':'Proceed with project-local work';
|
|
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>\`;
|
|
170
214
|
document.getElementById('app').innerHTML=\`
|
|
171
215
|
<header>
|
|
172
216
|
<div>
|
|
@@ -176,6 +220,12 @@ document.getElementById('app').innerHTML=\`
|
|
|
176
220
|
</div>
|
|
177
221
|
<div class="stamp"><b>\${warnings.length?'review':'clear'}</b><span>\${esc(manifest.workspace.name)}</span><span>\${esc(manifest.generatedAt)}</span></div>
|
|
178
222
|
</header>
|
|
223
|
+
<section class="audit" aria-label="Audit summary">
|
|
224
|
+
\${auditItem('AI decision',reviewRequired?'review required':'can proceed',nextAction,reviewRequired?'review':'primary')}
|
|
225
|
+
\${auditItem('Open intents',String(intents.length),intents.length?'Resolve or coordinate before changes':'No pending env changes')}
|
|
226
|
+
\${auditItem('Warnings',String(warnings.length),warnings.length?'Policy or drift needs attention':'No warnings detected')}
|
|
227
|
+
\${auditItem('Recent changes',String(recentChanges),recentChanges?'Check ledger before continuing':'No recent env ledger entries')}
|
|
228
|
+
</section>
|
|
179
229
|
<section class="metrics">
|
|
180
230
|
<div class="metric"><div class="num">\${entries(manifest.runtimes).length}</div><div class="label">runtimes</div></div>
|
|
181
231
|
<div class="metric"><div class="num">\${entries(manifest.packageManagers).length}</div><div class="label">package managers</div></div>
|
|
@@ -196,6 +246,8 @@ document.getElementById('app').innerHTML=\`
|
|
|
196
246
|
<div style="height:14px"></div>
|
|
197
247
|
\${card('Agent Intents','<span class="pill">'+intents.length+' open</span>',intentsHtml)}
|
|
198
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>
|
|
199
251
|
\${card('Agent Pointers','<span class="pill">'+entries(manifest.agentFiles).filter(([,v])=>v).length+' detected</span>','<div class="agents">'+agentCards+'</div>')}
|
|
200
252
|
<div style="height:14px"></div>
|
|
201
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>\`)}
|