@indy2kro/agentenv 0.2.2 → 0.3.0
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/README.md +46 -39
- package/dist/adapters/cursor.d.ts +1 -1
- package/dist/adapters/cursor.d.ts.map +1 -1
- package/dist/adapters/cursor.js +5 -1
- package/dist/adapters/cursor.js.map +1 -1
- package/dist/adapters/gemini.d.ts +1 -1
- package/dist/adapters/gemini.js +1 -1
- package/dist/adapters/rtk-delegation.d.ts +7 -0
- package/dist/adapters/rtk-delegation.d.ts.map +1 -1
- package/dist/adapters/rtk-delegation.js +5 -3
- package/dist/adapters/rtk-delegation.js.map +1 -1
- package/dist/adapters/vibe.d.ts +1 -1
- package/dist/adapters/vibe.js +1 -1
- package/dist/adapters/windsurf.d.ts +1 -1
- package/dist/adapters/windsurf.js +1 -1
- package/dist/cli/exit.d.ts +19 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +36 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/commands/apply.d.ts +2 -2
- package/dist/commands/apply.d.ts.map +1 -1
- package/dist/commands/apply.js +25 -1
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/completion.d.ts +30 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +181 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/doctor.d.ts +15 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +79 -8
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/setup.d.ts +4 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +20 -63
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts +124 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +440 -135
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/uninstall.d.ts +54 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +246 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +78 -34
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/wizard.d.ts +8 -0
- package/dist/commands/wizard.d.ts.map +1 -0
- package/dist/commands/{configure.js → wizard.js} +81 -69
- package/dist/commands/wizard.js.map +1 -0
- package/dist/config/schema.d.ts +2 -3
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +2 -11
- package/dist/config/schema.js.map +1 -1
- package/dist/config/scopes.d.ts.map +1 -1
- package/dist/config/scopes.js +4 -0
- package/dist/config/scopes.js.map +1 -1
- package/dist/generate/agentsmd.d.ts.map +1 -1
- package/dist/generate/agentsmd.js +17 -1
- package/dist/generate/agentsmd.js.map +1 -1
- package/dist/index.js +35 -8
- package/dist/index.js.map +1 -1
- package/dist/shell/detector.js +1 -1
- package/dist/shell/detector.js.map +1 -1
- package/dist/toolchain/fallbacks.d.ts +1 -2
- package/dist/toolchain/fallbacks.d.ts.map +1 -1
- package/dist/toolchain/fallbacks.js +2 -22
- package/dist/toolchain/fallbacks.js.map +1 -1
- package/dist/toolchain/mise.d.ts +33 -2
- package/dist/toolchain/mise.d.ts.map +1 -1
- package/dist/toolchain/mise.js +65 -12
- package/dist/toolchain/mise.js.map +1 -1
- package/dist/toolchain/rtk.d.ts +1 -1
- package/dist/toolchain/rtk.d.ts.map +1 -1
- package/dist/toolchain/rtk.js +9 -5
- package/dist/toolchain/rtk.js.map +1 -1
- package/dist/ui/output.d.ts +29 -0
- package/dist/ui/output.d.ts.map +1 -0
- package/dist/ui/output.js +72 -0
- package/dist/ui/output.js.map +1 -0
- package/dist/ui/spinner.d.ts +5 -1
- package/dist/ui/spinner.d.ts.map +1 -1
- package/dist/ui/spinner.js +13 -2
- package/dist/ui/spinner.js.map +1 -1
- package/dist/wizard/build.d.ts +17 -1
- package/dist/wizard/build.d.ts.map +1 -1
- package/dist/wizard/build.js +46 -1
- package/dist/wizard/build.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/configure.d.ts +0 -14
- package/dist/commands/configure.d.ts.map +0 -1
- package/dist/commands/configure.js.map +0 -1
package/dist/commands/status.js
CHANGED
|
@@ -3,11 +3,13 @@ import * as fs from 'fs';
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { isAgentInstalled, resolveBinary } from '../adapters/detect.js';
|
|
5
5
|
import { BINARY_MAP, TOOL_DESCRIPTIONS, TOOL_KEYS, TOOL_TIERS, getEnabledAgents, loadConfig, resolveIntegrationScope, validateConfig, } from '../config/schema.js';
|
|
6
|
-
import { findConfigPath, resolveScopeDir } from '../config/scopes.js';
|
|
6
|
+
import { findConfigPath, resolveScopeDir, userConfigDir } from '../config/scopes.js';
|
|
7
7
|
import { checkAgentShellConfiguration, detectShell } from '../shell/detector.js';
|
|
8
8
|
import { SuperpowersAdapter, ghAuthLine } from '../integrations/index.js';
|
|
9
9
|
import { resolveGhAuthProbe } from '../toolchain/gh.js';
|
|
10
|
+
import { MISE_TOOL_NAMES, PINNED_TOOL_VERSIONS, getInstalledToolState, getMiseVersion, } from '../toolchain/mise.js';
|
|
10
11
|
import { colorizeLine, theme } from '../ui/theme.js';
|
|
12
|
+
import { renderLogo, resolveResultLine, setQuietEnabled } from '../ui/output.js';
|
|
11
13
|
const AGENT_CONFIG_FILES = {
|
|
12
14
|
claude_code: {
|
|
13
15
|
label: 'Claude Code',
|
|
@@ -30,10 +32,32 @@ const AGENT_CONFIG_FILES = {
|
|
|
30
32
|
vibe: { label: 'Mistral Vibe', check: (baseDir) => path.join(baseDir, 'RTK.md') },
|
|
31
33
|
};
|
|
32
34
|
export { AGENT_CONFIG_FILES };
|
|
35
|
+
export function computeStatusExitCode(report) {
|
|
36
|
+
const drifted = report.config === null ||
|
|
37
|
+
report.validation.errors.length > 0 ||
|
|
38
|
+
report.tools.some((tool) => tool.drift) ||
|
|
39
|
+
report.agents.some((agent) => agent.drift) ||
|
|
40
|
+
report.generated.some((entry) => !entry.exists || !entry.managed) ||
|
|
41
|
+
report.integrations.some((integration) => integration.drift) ||
|
|
42
|
+
report.customTools.some((tool) => tool.drift);
|
|
43
|
+
return drifted ? 1 : 0;
|
|
44
|
+
}
|
|
45
|
+
const defaultSuperpowersStatus = async (baseDir, config) => {
|
|
46
|
+
const adapter = new SuperpowersAdapter();
|
|
47
|
+
return adapter.status(baseDir, config);
|
|
48
|
+
};
|
|
33
49
|
function homeDir() {
|
|
34
50
|
return process.env.HOME || process.env.USERPROFILE || '';
|
|
35
51
|
}
|
|
36
|
-
function
|
|
52
|
+
function norm(p) {
|
|
53
|
+
return path.resolve(p).replace(/\\/g, '/').toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
function scopeFromConfigPath(configPath) {
|
|
56
|
+
return norm(configPath) === norm(path.join(userConfigDir(), 'agentenv.toml'))
|
|
57
|
+
? 'user'
|
|
58
|
+
: 'project';
|
|
59
|
+
}
|
|
60
|
+
function hasManagedMarker(file, config) {
|
|
37
61
|
try {
|
|
38
62
|
const content = fs.readFileSync(file, 'utf-8');
|
|
39
63
|
const marker = config.generate?.marker_start ?? '<!-- agentenv-managed-start -->';
|
|
@@ -43,172 +67,453 @@ function containsManagedMarker(file, config) {
|
|
|
43
67
|
return false;
|
|
44
68
|
}
|
|
45
69
|
}
|
|
46
|
-
function
|
|
47
|
-
if (tool.already_installed) {
|
|
48
|
-
const candidate = pathForPlatform(tool);
|
|
49
|
-
if (candidate && fs.existsSync(candidate))
|
|
50
|
-
return `present (${candidate})`;
|
|
51
|
-
return 'MISSING on disk';
|
|
52
|
-
}
|
|
53
|
-
return `mise source: ${tool.mise_source}${tool.version ? ` (${tool.version})` : ''}`;
|
|
54
|
-
}
|
|
55
|
-
function pathForPlatform(tool) {
|
|
70
|
+
function customToolPath(tool) {
|
|
56
71
|
if (process.platform === 'win32')
|
|
57
72
|
return tool.path_windows;
|
|
58
73
|
if (process.platform === 'darwin')
|
|
59
74
|
return tool.path_macos;
|
|
60
75
|
return tool.path_linux;
|
|
61
76
|
}
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
function customToolStatus(tool, exists) {
|
|
78
|
+
if (tool.already_installed) {
|
|
79
|
+
const candidate = customToolPath(tool);
|
|
80
|
+
const pathExists = candidate !== undefined && exists(candidate);
|
|
81
|
+
return {
|
|
82
|
+
status: candidate && pathExists ? `present (${candidate})` : 'MISSING on disk',
|
|
83
|
+
drift: !pathExists,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
status: `mise source: ${tool.mise_source}${tool.version ? ` (${tool.version})` : ''}`,
|
|
88
|
+
drift: false,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function tier0Report(shell, enabledAgents, deps) {
|
|
92
|
+
const isWindows = shell.isWindows;
|
|
93
|
+
const shellHome = homeDir();
|
|
94
|
+
const agentChecks = isWindows === true
|
|
95
|
+
? enabledAgents.map((agent) => ({
|
|
96
|
+
agent,
|
|
97
|
+
label: AGENT_CONFIG_FILES[agent]?.label ?? agent,
|
|
98
|
+
needsFix: (deps.checkAgentShellConfiguration ?? checkAgentShellConfiguration)(agent, shellHome).needsFix,
|
|
99
|
+
}))
|
|
100
|
+
: [];
|
|
101
|
+
return {
|
|
102
|
+
isWindows,
|
|
103
|
+
currentShell: shell.currentShell,
|
|
104
|
+
gitBashPath: shell.gitBashPath ?? null,
|
|
105
|
+
posixCompatible: shell.isPosixCompatible,
|
|
106
|
+
missingUtilities: shell.missingUtilities,
|
|
107
|
+
agentChecks,
|
|
108
|
+
needsFix: isWindows && (!shell.gitBashPath || agentChecks.some((check) => check.needsFix)),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Gather the full status report (structured, no printing). */
|
|
112
|
+
export async function gatherStatus(deps = {}) {
|
|
113
|
+
const getMiseVersionFn = deps.getMiseVersion ?? getMiseVersion;
|
|
114
|
+
const configPath = (deps.findConfigPath ?? findConfigPath)();
|
|
68
115
|
if (!configPath) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
116
|
+
const report = {
|
|
117
|
+
command: 'status',
|
|
118
|
+
config: null,
|
|
119
|
+
scope: null,
|
|
120
|
+
baseDir: null,
|
|
121
|
+
exitCode: 0,
|
|
122
|
+
validation: { errors: [], warnings: [] },
|
|
123
|
+
agents: [],
|
|
124
|
+
tools: [],
|
|
125
|
+
customTools: [],
|
|
126
|
+
generated: [],
|
|
127
|
+
integrations: [],
|
|
128
|
+
rtkEnabled: false,
|
|
129
|
+
tier0: null,
|
|
130
|
+
ghAuth: null,
|
|
131
|
+
miseVersion: getMiseVersionFn(),
|
|
132
|
+
integrationDetails: [],
|
|
133
|
+
};
|
|
134
|
+
return { ...report, exitCode: computeStatusExitCode(report) };
|
|
73
135
|
}
|
|
74
136
|
let config;
|
|
75
137
|
try {
|
|
76
|
-
config = loadConfig();
|
|
138
|
+
config = (deps.loadConfig ?? loadConfig)(configPath);
|
|
77
139
|
}
|
|
78
140
|
catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
141
|
+
const scope = scopeFromConfigPath(configPath);
|
|
142
|
+
const report = {
|
|
143
|
+
command: 'status',
|
|
144
|
+
config: configPath,
|
|
145
|
+
scope,
|
|
146
|
+
baseDir: (deps.resolveScopeDir ?? resolveScopeDir)(scope),
|
|
147
|
+
exitCode: 0,
|
|
148
|
+
validation: {
|
|
149
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
150
|
+
warnings: [],
|
|
151
|
+
},
|
|
152
|
+
agents: [],
|
|
153
|
+
tools: [],
|
|
154
|
+
customTools: [],
|
|
155
|
+
generated: [],
|
|
156
|
+
integrations: [],
|
|
157
|
+
rtkEnabled: false,
|
|
158
|
+
tier0: null,
|
|
159
|
+
ghAuth: null,
|
|
160
|
+
miseVersion: getMiseVersionFn(),
|
|
161
|
+
integrationDetails: [],
|
|
162
|
+
};
|
|
163
|
+
return { ...report, exitCode: computeStatusExitCode(report) };
|
|
164
|
+
}
|
|
165
|
+
const resolveDir = deps.resolveScopeDir ?? resolveScopeDir;
|
|
166
|
+
const baseDir = resolveDir(config.scope);
|
|
167
|
+
const validation = (deps.validateConfig ?? validateConfig)(config);
|
|
168
|
+
const shell = (deps.detectShell ?? detectShell)();
|
|
169
|
+
const enabledAgents = (deps.getEnabledAgents ?? getEnabledAgents)(config);
|
|
170
|
+
const exists = deps.fileExists ?? fs.existsSync;
|
|
171
|
+
const rtkEnabled = config.rtk?.enabled === true;
|
|
172
|
+
const agents = enabledAgents.map((agent) => {
|
|
173
|
+
const meta = AGENT_CONFIG_FILES[agent];
|
|
174
|
+
const installed = (deps.isAgentInstalled ?? isAgentInstalled)(agent);
|
|
175
|
+
const configured = exists(meta.check(baseDir));
|
|
176
|
+
return {
|
|
177
|
+
key: agent,
|
|
178
|
+
label: meta.label,
|
|
179
|
+
installed,
|
|
180
|
+
configured,
|
|
181
|
+
drift: installed && !configured,
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
const enabledTools = TOOL_KEYS.filter((key) => config.tools?.[key] === true);
|
|
185
|
+
let ghAuth = null;
|
|
186
|
+
const installedState = (deps.getInstalledToolState ?? getInstalledToolState)();
|
|
187
|
+
const hasVersionData = Object.keys(installedState).length > 0;
|
|
188
|
+
const tools = enabledTools.map((key) => {
|
|
189
|
+
const binary = BINARY_MAP[key];
|
|
190
|
+
const found = (deps.resolveBinary ?? resolveBinary)(binary) !== null;
|
|
191
|
+
if (key === 'gh' && found) {
|
|
192
|
+
ghAuth = ghAuthLine((deps.resolveGhAuthProbe ?? resolveGhAuthProbe)()().status);
|
|
193
|
+
}
|
|
194
|
+
const miseName = MISE_TOOL_NAMES[key] || key;
|
|
195
|
+
const state = installedState[miseName];
|
|
196
|
+
const pinned = config.tool_versions?.[key] ?? PINNED_TOOL_VERSIONS[miseName] ?? null;
|
|
197
|
+
const installedVersions = state?.versions ?? [];
|
|
198
|
+
const installed = hasVersionData && installedVersions.length > 0
|
|
199
|
+
? installedVersions[installedVersions.length - 1]
|
|
200
|
+
: null;
|
|
201
|
+
const versionDrift = pinned !== null &&
|
|
202
|
+
installed !== null &&
|
|
203
|
+
installedVersions.length > 0 &&
|
|
204
|
+
!installedVersions.includes(pinned);
|
|
205
|
+
return {
|
|
206
|
+
key,
|
|
207
|
+
binary,
|
|
208
|
+
tier: TOOL_TIERS[key] ?? 0,
|
|
209
|
+
found,
|
|
210
|
+
drift: !found || versionDrift,
|
|
211
|
+
pinned,
|
|
212
|
+
installed,
|
|
213
|
+
};
|
|
214
|
+
});
|
|
215
|
+
const customTools = (config.custom_tools ?? []).map((tool) => {
|
|
216
|
+
const { status, drift } = customToolStatus(tool, exists);
|
|
217
|
+
return { name: tool.name, status, drift };
|
|
218
|
+
});
|
|
219
|
+
const generatedEntries = [
|
|
220
|
+
['mise.toml', path.join(baseDir, 'mise.toml'), false],
|
|
221
|
+
['AGENTS.md', path.join(baseDir, 'AGENTS.md'), true],
|
|
222
|
+
['CLAUDE.md', path.join(baseDir, 'CLAUDE.md'), true],
|
|
223
|
+
];
|
|
224
|
+
const generated = generatedEntries.map(([label, file, markerCheck]) => {
|
|
225
|
+
const generatedExists = exists(file);
|
|
226
|
+
const managed = generatedExists &&
|
|
227
|
+
(markerCheck ? (deps.hasManagedMarker ?? hasManagedMarker)(file, config) : true);
|
|
228
|
+
return { label, exists: generatedExists, managed };
|
|
229
|
+
});
|
|
230
|
+
const integrations = [];
|
|
231
|
+
const integrationDetails = [];
|
|
232
|
+
const integrationKey = 'superpowers';
|
|
233
|
+
const superpowersConfig = config.integrations?.superpowers;
|
|
234
|
+
if (superpowersConfig?.enabled === true) {
|
|
235
|
+
// Resolve against the top-level scope before calling the adapter — the
|
|
236
|
+
// adapter only ever sees an IntegrationConfig, not the full
|
|
237
|
+
// AgentenvConfig, so it can't fall back to the top-level scope itself
|
|
238
|
+
// (see the matching resolution in apply.ts).
|
|
239
|
+
const scope = resolveIntegrationScope(config, superpowersConfig);
|
|
240
|
+
const result = await (deps.superpowersStatus ?? defaultSuperpowersStatus)(resolveDir(scope), {
|
|
241
|
+
...superpowersConfig,
|
|
242
|
+
scope,
|
|
243
|
+
});
|
|
244
|
+
integrations.push({
|
|
245
|
+
key: integrationKey,
|
|
246
|
+
enabled: true,
|
|
247
|
+
source: result.source ?? null,
|
|
248
|
+
ref: result.ref ?? null,
|
|
249
|
+
scope: result.scope,
|
|
250
|
+
agents: superpowersConfig.agents ?? [],
|
|
251
|
+
states: result.agents.map(({ agent, state, detail }) => ({
|
|
252
|
+
agent,
|
|
253
|
+
state,
|
|
254
|
+
detail: detail ?? null,
|
|
255
|
+
})),
|
|
256
|
+
drift: result.agents.some((entry) => entry.state === 'missing' || entry.state === 'drifted'),
|
|
257
|
+
});
|
|
258
|
+
integrationDetails.push({
|
|
259
|
+
key: integrationKey,
|
|
260
|
+
hooksAllowed: superpowersConfig.allow_hooks ?? false,
|
|
261
|
+
externalRequestsAllowed: superpowersConfig.allow_external_requests ?? false,
|
|
262
|
+
warnings: result.warnings,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
integrations.push({
|
|
267
|
+
key: integrationKey,
|
|
268
|
+
enabled: false,
|
|
269
|
+
source: null,
|
|
270
|
+
ref: null,
|
|
271
|
+
scope: null,
|
|
272
|
+
agents: [],
|
|
273
|
+
states: [],
|
|
274
|
+
drift: false,
|
|
275
|
+
});
|
|
276
|
+
integrationDetails.push({
|
|
277
|
+
key: integrationKey,
|
|
278
|
+
hooksAllowed: null,
|
|
279
|
+
externalRequestsAllowed: null,
|
|
280
|
+
warnings: [],
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
const report = {
|
|
284
|
+
command: 'status',
|
|
285
|
+
config: configPath,
|
|
286
|
+
scope: config.scope ?? 'project',
|
|
287
|
+
baseDir,
|
|
288
|
+
exitCode: 0,
|
|
289
|
+
validation,
|
|
290
|
+
agents,
|
|
291
|
+
tools,
|
|
292
|
+
customTools,
|
|
293
|
+
generated,
|
|
294
|
+
integrations,
|
|
295
|
+
rtkEnabled,
|
|
296
|
+
tier0: tier0Report(shell, enabledAgents, deps),
|
|
297
|
+
ghAuth,
|
|
298
|
+
miseVersion: getMiseVersionFn(),
|
|
299
|
+
integrationDetails,
|
|
300
|
+
};
|
|
301
|
+
return { ...report, exitCode: computeStatusExitCode(report) };
|
|
302
|
+
}
|
|
303
|
+
function statusSummary(report) {
|
|
304
|
+
if (report.config === null) {
|
|
305
|
+
return {
|
|
306
|
+
severity: 'fail',
|
|
307
|
+
headline: 'No configuration found',
|
|
308
|
+
summary: 'run `agentenv setup` or `agentenv apply` to get started',
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const issues = report.validation.errors.length +
|
|
312
|
+
report.tools.filter((tool) => tool.drift).length +
|
|
313
|
+
report.agents.filter((agent) => agent.drift).length +
|
|
314
|
+
report.customTools.filter((tool) => tool.drift).length +
|
|
315
|
+
report.generated.filter((entry) => !entry.exists || !entry.managed).length +
|
|
316
|
+
report.integrations.filter((integration) => integration.drift).length;
|
|
317
|
+
if (issues === 0) {
|
|
318
|
+
return { severity: 'ok', headline: 'Environment is clean' };
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
severity: 'fail',
|
|
322
|
+
headline: `Status: ${issues} issue${issues === 1 ? '' : 's'} found`,
|
|
323
|
+
summary: 'run `agentenv apply` to fix, or `agentenv update` for new versions',
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
export function statusToJson(report) {
|
|
327
|
+
return {
|
|
328
|
+
command: report.command,
|
|
329
|
+
config: report.config,
|
|
330
|
+
scope: report.scope,
|
|
331
|
+
baseDir: report.baseDir,
|
|
332
|
+
exitCode: report.exitCode,
|
|
333
|
+
validation: report.validation,
|
|
334
|
+
agents: report.agents,
|
|
335
|
+
tools: report.tools,
|
|
336
|
+
customTools: report.customTools,
|
|
337
|
+
generated: report.generated,
|
|
338
|
+
integrations: report.integrations,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function displayName(key) {
|
|
342
|
+
return key.charAt(0).toUpperCase() + key.slice(1);
|
|
343
|
+
}
|
|
344
|
+
/** Collapsed one-line-per-area view for `status --short`. */
|
|
345
|
+
export function renderStatusShort(report) {
|
|
346
|
+
const chunks = [];
|
|
347
|
+
chunks.push(`Config: ${report.config ?? '(none)'}`);
|
|
348
|
+
if (report.config !== null) {
|
|
349
|
+
chunks.push(`Scope: ${report.scope ?? 'project'}`);
|
|
350
|
+
chunks.push(`Base directory: ${report.baseDir}`);
|
|
351
|
+
}
|
|
352
|
+
const toolDrift = report.tools.filter((tool) => tool.drift).length;
|
|
353
|
+
chunks.push(`Tools: ${report.tools.length} configured${toolDrift > 0 ? `, ${toolDrift} drifted` : ''}`);
|
|
354
|
+
const agentDrift = report.agents.filter((agent) => agent.drift).length;
|
|
355
|
+
chunks.push(`Agents: ${report.agents.length} enabled${agentDrift > 0 ? `, ${agentDrift} drifted` : ''}`);
|
|
356
|
+
if (report.customTools.length > 0) {
|
|
357
|
+
const customDrift = report.customTools.filter((tool) => tool.drift).length;
|
|
358
|
+
chunks.push(`Custom tools: ${report.customTools.length}${customDrift > 0 ? `, ${customDrift} drifted` : ''}`);
|
|
359
|
+
}
|
|
360
|
+
const generatedMissing = report.generated.filter((entry) => !entry.exists || !entry.managed).length;
|
|
361
|
+
chunks.push(`Generated files: ${report.generated.length}${generatedMissing > 0 ? `, ${generatedMissing} missing/unmanaged` : ''}`);
|
|
362
|
+
if (report.integrations.length > 0) {
|
|
363
|
+
const integrationDrift = report.integrations.filter((integration) => integration.drift).length;
|
|
364
|
+
chunks.push(`Integrations: ${report.integrations.length}${integrationDrift > 0 ? `, ${integrationDrift} drifted` : ''}`);
|
|
365
|
+
}
|
|
366
|
+
if (report.validation.errors.length > 0) {
|
|
367
|
+
chunks.push(`Config errors: ${report.validation.errors.length}`);
|
|
368
|
+
}
|
|
369
|
+
if (report.validation.warnings.length > 0) {
|
|
370
|
+
chunks.push(`Warnings: ${report.validation.warnings.length}`);
|
|
371
|
+
}
|
|
372
|
+
for (const warning of report.validation.warnings)
|
|
373
|
+
chunks.push(theme.warn(` warning: ${warning}`));
|
|
374
|
+
return `${chunks.join('\n')}\n`;
|
|
375
|
+
}
|
|
376
|
+
/** Render the human report body (banners are emitted by the command). */
|
|
377
|
+
export function renderStatus(report) {
|
|
378
|
+
if (report.config === null) {
|
|
379
|
+
return [
|
|
380
|
+
'No agentenv.toml found (project or user scope).',
|
|
381
|
+
' Run `agentenv setup` (alias: `configure`) to create one.',
|
|
382
|
+
'',
|
|
383
|
+
].join('\n');
|
|
384
|
+
}
|
|
385
|
+
const chunks = [];
|
|
386
|
+
chunks.push(`Config: ${report.config}`);
|
|
387
|
+
chunks.push(`Scope: ${report.scope ?? 'project'}`);
|
|
388
|
+
chunks.push(`Base directory: ${report.baseDir}`);
|
|
389
|
+
chunks.push(`Mise: ${report.miseVersion}`);
|
|
390
|
+
const validationSummary = `Validation: ${report.validation.errors.length === 0 ? 'valid' : `${report.validation.errors.length} error(s)`}${report.validation.warnings.length > 0 ? `, ${report.validation.warnings.length} warning(s)` : ''}`;
|
|
391
|
+
chunks.push(report.validation.errors.length === 0
|
|
392
|
+
? theme.ok(validationSummary)
|
|
393
|
+
: theme.fail(validationSummary));
|
|
394
|
+
for (const warning of report.validation.warnings)
|
|
395
|
+
chunks.push(theme.warn(` warning: ${warning}`));
|
|
396
|
+
chunks.push(`RTK command rewriting: ${report.rtkEnabled ? 'enabled' : 'disabled'}`);
|
|
93
397
|
// Tier 0 shell status
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}));
|
|
112
|
-
if (agentShellChecks.length > 0) {
|
|
113
|
-
console.log(' Agent shell overrides:');
|
|
114
|
-
for (const { agent, check } of agentShellChecks) {
|
|
115
|
-
const label = AGENT_CONFIG_FILES[agent]?.label ?? agent;
|
|
116
|
-
console.log(colorizeLine(` ${check.needsFix ? '✗' : '✓'} ${label}`));
|
|
398
|
+
if (report.tier0) {
|
|
399
|
+
chunks.push(theme.heading('\nTier 0 (shell):'));
|
|
400
|
+
const tier0 = report.tier0;
|
|
401
|
+
if (tier0.isWindows) {
|
|
402
|
+
chunks.push(` Current shell: ${tier0.currentShell}`);
|
|
403
|
+
if (tier0.gitBashPath)
|
|
404
|
+
chunks.push(` Git Bash: ${tier0.gitBashPath}`);
|
|
405
|
+
else
|
|
406
|
+
chunks.push(' Git Bash: NOT FOUND');
|
|
407
|
+
if (tier0.agentChecks.length > 0) {
|
|
408
|
+
chunks.push(' Agent shell overrides:');
|
|
409
|
+
for (const check of tier0.agentChecks) {
|
|
410
|
+
chunks.push(colorizeLine(` ${check.needsFix ? '✗' : '✓'} ${check.label}`));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (tier0.needsFix) {
|
|
414
|
+
chunks.push(theme.warn(' Fix: run `agentenv apply` (Tier 0 shell fix)'));
|
|
117
415
|
}
|
|
118
416
|
}
|
|
119
|
-
|
|
120
|
-
|
|
417
|
+
else {
|
|
418
|
+
chunks.push(` ${tier0.posixCompatible ? 'POSIX-compatible' : 'non-POSIX'} (not Windows; Tier 0 N/A)`);
|
|
419
|
+
if (tier0.missingUtilities.length > 0) {
|
|
420
|
+
chunks.push(` Missing utilities: ${tier0.missingUtilities.join(', ')}`);
|
|
421
|
+
}
|
|
121
422
|
}
|
|
122
423
|
}
|
|
123
|
-
else {
|
|
124
|
-
console.log(` ${shell.isPosixCompatible ? 'POSIX-compatible' : 'non-POSIX'} (not Windows; Tier 0 N/A)`);
|
|
125
|
-
const missing = shell.missingUtilities;
|
|
126
|
-
if (missing.length > 0)
|
|
127
|
-
console.log(` Missing utilities: ${missing.join(', ')}`);
|
|
128
|
-
}
|
|
129
424
|
// Agents
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
console.log(' (none enabled)');
|
|
425
|
+
chunks.push(theme.heading('\nAgents:'));
|
|
426
|
+
if (report.agents.length === 0) {
|
|
427
|
+
chunks.push(' (none enabled)');
|
|
134
428
|
}
|
|
135
|
-
for (const agent of
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const drift = installed && !configured;
|
|
140
|
-
const line = ` ${meta.label.padEnd(16)} installed: ${installed ? 'yes' : 'no'} ` +
|
|
141
|
-
`configured: ${configured ? 'yes' : 'no'}${drift ? ' <- drift: installed but not configured' : ''}`;
|
|
142
|
-
console.log(drift ? theme.warn(line) : line);
|
|
429
|
+
for (const agent of report.agents) {
|
|
430
|
+
const line = ` ${agent.label.padEnd(16)} installed: ${agent.installed ? 'yes' : 'no'} ` +
|
|
431
|
+
`configured: ${agent.configured ? 'yes' : 'no'}${agent.drift ? ' <- drift: installed but not configured' : ''}`;
|
|
432
|
+
chunks.push(agent.drift ? theme.warn(line) : line);
|
|
143
433
|
}
|
|
144
434
|
// Tools
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
435
|
+
chunks.push(theme.heading('\nTools:'));
|
|
436
|
+
for (const tool of report.tools) {
|
|
437
|
+
const desc = TOOL_DESCRIPTIONS[tool.key] ?? '';
|
|
438
|
+
const versionTail = !tool.found
|
|
439
|
+
? ''
|
|
440
|
+
: tool.pinned !== null
|
|
441
|
+
? tool.installed !== null && tool.installed !== tool.pinned
|
|
442
|
+
? ` <- drift: version ${tool.pinned} configured, ${tool.installed} installed`
|
|
443
|
+
: ` (${tool.pinned} installed)`
|
|
444
|
+
: tool.installed !== null
|
|
445
|
+
? ` (${tool.installed})`
|
|
446
|
+
: '';
|
|
447
|
+
chunks.push(colorizeLine(` ${tool.found ? '✓' : '✗'} ${tool.binary.padEnd(12)} ${tool.key} (Tier ${tool.tier})${tool.found ? `${versionTail}` : ' <- drift: enabled in config but not on PATH'} — ${desc}`));
|
|
448
|
+
if (tool.key === 'gh' && report.ghAuth) {
|
|
449
|
+
chunks.push(colorizeLine(` ${report.ghAuth}`));
|
|
155
450
|
}
|
|
156
451
|
}
|
|
157
|
-
if (
|
|
158
|
-
|
|
452
|
+
if (report.tools.length === 0)
|
|
453
|
+
chunks.push(' (none enabled)');
|
|
159
454
|
// Custom tools
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
console.log(' (none)');
|
|
455
|
+
chunks.push(theme.heading('\nCustom tools:'));
|
|
456
|
+
if (report.customTools.length === 0) {
|
|
457
|
+
chunks.push(' (none)');
|
|
164
458
|
}
|
|
165
|
-
for (const tool of customTools) {
|
|
166
|
-
|
|
459
|
+
for (const tool of report.customTools) {
|
|
460
|
+
chunks.push(` ${tool.name}: ${tool.status}`);
|
|
167
461
|
}
|
|
168
462
|
// Generated files
|
|
169
|
-
|
|
170
|
-
const generated
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
['CLAUDE.md', path.join(baseDir, 'CLAUDE.md'), true],
|
|
174
|
-
];
|
|
175
|
-
for (const [label, file, markerCheck] of generated) {
|
|
176
|
-
const exists = fs.existsSync(file);
|
|
177
|
-
if (!exists) {
|
|
178
|
-
console.log(theme.fail(` ✗ ${label} (missing)`));
|
|
463
|
+
chunks.push(theme.heading('\nGenerated files:'));
|
|
464
|
+
for (const entry of report.generated) {
|
|
465
|
+
if (!entry.exists) {
|
|
466
|
+
chunks.push(theme.fail(` ✗ ${entry.label} (missing)`));
|
|
179
467
|
continue;
|
|
180
468
|
}
|
|
181
|
-
|
|
182
|
-
console.log(colorizeLine(` ✓ ${label}${managed ? '' : ' (managed marker block missing)'}`));
|
|
469
|
+
chunks.push(colorizeLine(` ✓ ${entry.label}${entry.managed ? '' : ' (managed marker block missing)'}`));
|
|
183
470
|
}
|
|
184
471
|
// Integrations
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
const adapter = new SuperpowersAdapter();
|
|
198
|
-
const result = await adapter.status(resolveScopeDir(scope), { ...superpowersConfig, scope });
|
|
199
|
-
console.log(' enabled: yes');
|
|
200
|
-
console.log(` source: ${result.source ?? '(unset)'}`);
|
|
201
|
-
console.log(` ref: ${result.ref ?? '(unset)'}`);
|
|
202
|
-
console.log(` scope: ${result.scope}`);
|
|
203
|
-
for (const agentState of result.agents) {
|
|
472
|
+
chunks.push(theme.heading('\nIntegrations:'));
|
|
473
|
+
for (const integration of report.integrations) {
|
|
474
|
+
chunks.push(` ${displayName(integration.key)}`);
|
|
475
|
+
if (!integration.enabled) {
|
|
476
|
+
chunks.push(' enabled: no');
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
chunks.push(' enabled: yes');
|
|
480
|
+
chunks.push(` source: ${integration.source ?? '(unset)'}`);
|
|
481
|
+
chunks.push(` ref: ${integration.ref ?? '(unset)'}`);
|
|
482
|
+
chunks.push(` scope: ${integration.scope}`);
|
|
483
|
+
for (const agentState of integration.states) {
|
|
204
484
|
const label = AGENT_CONFIG_FILES[agentState.agent]?.label ?? agentState.agent;
|
|
205
|
-
|
|
485
|
+
chunks.push(` ${label.padEnd(16)} ${agentState.state}${agentState.detail ? ` (${agentState.detail})` : ''}`);
|
|
486
|
+
}
|
|
487
|
+
const details = report.integrationDetails.find((detail) => detail.key === integration.key);
|
|
488
|
+
chunks.push(` hooks allowed: ${details?.hooksAllowed ? 'yes' : 'no'}`);
|
|
489
|
+
chunks.push(` external requests allowed: ${details?.externalRequestsAllowed ? 'yes' : 'no'}`);
|
|
490
|
+
for (const warning of details?.warnings ?? []) {
|
|
491
|
+
chunks.push(theme.warn(` warning: ${warning}`));
|
|
206
492
|
}
|
|
207
|
-
console.log(` hooks allowed: ${superpowersConfig.allow_hooks ? 'yes' : 'no'}`);
|
|
208
|
-
console.log(` external requests allowed: ${superpowersConfig.allow_external_requests ? 'yes' : 'no'}`);
|
|
209
|
-
for (const warning of result.warnings)
|
|
210
|
-
console.log(theme.warn(` warning: ${warning}`));
|
|
211
493
|
}
|
|
212
|
-
|
|
494
|
+
return chunks.join('\n') + '\n';
|
|
495
|
+
}
|
|
496
|
+
export const statusCommand = new Command()
|
|
497
|
+
.name('status')
|
|
498
|
+
.description('Show current configuration and environment status')
|
|
499
|
+
.option('--json', 'emit a machine-readable JSON document on stdout')
|
|
500
|
+
.option('--short', 'collapsed one-line-per-area report (no per-item detail)')
|
|
501
|
+
.action(async (options) => {
|
|
502
|
+
const json = options.json === true;
|
|
503
|
+
const short = options.short === true;
|
|
504
|
+
if (json)
|
|
505
|
+
setQuietEnabled(true);
|
|
506
|
+
renderLogo();
|
|
507
|
+
const report = await gatherStatus();
|
|
508
|
+
if (json) {
|
|
509
|
+
console.log(JSON.stringify(statusToJson(report), null, 2));
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
process.stdout.write(short ? renderStatusShort(report) : renderStatus(report));
|
|
513
|
+
const summary = statusSummary(report);
|
|
514
|
+
console.log(resolveResultLine(summary));
|
|
515
|
+
}
|
|
516
|
+
if (report.exitCode === 1)
|
|
517
|
+
process.exitCode = 1;
|
|
213
518
|
});
|
|
214
519
|
//# sourceMappingURL=status.js.map
|