@magclaw/cli-core 0.1.31 → 0.1.32
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/package.json +1 -1
- package/src/cli.js +81 -32
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1118,6 +1118,10 @@ function defaultCliNpmPath(env = process.env) {
|
|
|
1118
1118
|
return commandExists('npm', env) || (process.platform === 'win32' ? 'npm.cmd' : 'npm');
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
|
+
function contentHash(value = '') {
|
|
1122
|
+
return crypto.createHash('sha256').update(String(value || '')).digest('hex');
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1121
1125
|
function cliShimTargets({ packageSpec = '@magclaw/cli-core@latest', computerPackageSpec = '@magclaw/computer@latest' } = {}) {
|
|
1122
1126
|
return [
|
|
1123
1127
|
{
|
|
@@ -1146,9 +1150,11 @@ export function renderCliShimFiles({
|
|
|
1146
1150
|
return targets.flatMap((target) => [
|
|
1147
1151
|
{
|
|
1148
1152
|
name: `${target.command}.cmd`,
|
|
1153
|
+
command: target.command,
|
|
1149
1154
|
executable: true,
|
|
1150
1155
|
content: [
|
|
1151
1156
|
'@echo off',
|
|
1157
|
+
`rem MagClaw CLI shim generated by @magclaw/cli-core ${DAEMON_VERSION}.`,
|
|
1152
1158
|
'setlocal',
|
|
1153
1159
|
`set "NPM_BIN=${cmdEnvValue(targetNpm)}"`,
|
|
1154
1160
|
`if not exist "%NPM_BIN%" set "NPM_BIN=${cmdEnvValue(fallback)}"`,
|
|
@@ -1161,8 +1167,10 @@ export function renderCliShimFiles({
|
|
|
1161
1167
|
},
|
|
1162
1168
|
{
|
|
1163
1169
|
name: `${target.command}.ps1`,
|
|
1170
|
+
command: target.command,
|
|
1164
1171
|
executable: true,
|
|
1165
1172
|
content: [
|
|
1173
|
+
`# MagClaw CLI shim generated by @magclaw/cli-core ${DAEMON_VERSION}.`,
|
|
1166
1174
|
`$npmBin = ${psSingleQuote(targetNpm)}`,
|
|
1167
1175
|
`if (-not (Test-Path -LiteralPath $npmBin)) { $npmBin = ${psSingleQuote(fallback)} }`,
|
|
1168
1176
|
`$packageSpec = ${psSingleQuote(target.packageSpec)}`,
|
|
@@ -1177,11 +1185,12 @@ export function renderCliShimFiles({
|
|
|
1177
1185
|
return targets.map((target) => (
|
|
1178
1186
|
{
|
|
1179
1187
|
name: target.command,
|
|
1188
|
+
command: target.command,
|
|
1180
1189
|
executable: true,
|
|
1181
1190
|
content: [
|
|
1182
1191
|
'#!/bin/sh',
|
|
1183
1192
|
'set -eu',
|
|
1184
|
-
|
|
1193
|
+
`# MagClaw CLI shim generated by @magclaw/cli-core ${DAEMON_VERSION}.`,
|
|
1185
1194
|
`NPM_BIN=${shSingleQuote(targetNpm)}`,
|
|
1186
1195
|
`PACKAGE_SPEC=${shSingleQuote(target.packageSpec)}`,
|
|
1187
1196
|
'if [ ! -x "$NPM_BIN" ]; then',
|
|
@@ -1247,17 +1256,63 @@ async function existingDurableMagclawCommand(command = 'magclaw', env = process.
|
|
|
1247
1256
|
return existing;
|
|
1248
1257
|
}
|
|
1249
1258
|
|
|
1259
|
+
async function inspectCliShimFile(file, expectedContent) {
|
|
1260
|
+
const expectedHash = contentHash(expectedContent);
|
|
1261
|
+
let existing = null;
|
|
1262
|
+
try {
|
|
1263
|
+
existing = await readFile(file, 'utf8');
|
|
1264
|
+
} catch (error) {
|
|
1265
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
1266
|
+
}
|
|
1267
|
+
if (existing === null) {
|
|
1268
|
+
return {
|
|
1269
|
+
file,
|
|
1270
|
+
exists: false,
|
|
1271
|
+
generated: true,
|
|
1272
|
+
upToDate: false,
|
|
1273
|
+
reason: 'missing',
|
|
1274
|
+
currentHash: '',
|
|
1275
|
+
expectedHash,
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
const generated = isGeneratedMagClawShim(existing);
|
|
1279
|
+
const currentHash = contentHash(existing);
|
|
1280
|
+
return {
|
|
1281
|
+
file,
|
|
1282
|
+
exists: true,
|
|
1283
|
+
generated,
|
|
1284
|
+
upToDate: generated && currentHash === expectedHash,
|
|
1285
|
+
reason: generated ? (currentHash === expectedHash ? 'current' : 'outdated') : 'non_magclaw_command',
|
|
1286
|
+
currentHash,
|
|
1287
|
+
expectedHash,
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1250
1291
|
async function writeCliShimFile(file, content, { force = false } = {}) {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1292
|
+
const status = await inspectCliShimFile(file, content);
|
|
1293
|
+
if (status.exists && !status.generated && !force) {
|
|
1294
|
+
const error = new Error(`Refusing to overwrite existing non-MagClaw command: ${file}`);
|
|
1295
|
+
error.code = 'EEXIST';
|
|
1296
|
+
throw error;
|
|
1297
|
+
}
|
|
1298
|
+
if (status.upToDate && !force) {
|
|
1299
|
+
await chmod(file, 0o755).catch(() => {});
|
|
1300
|
+
return {
|
|
1301
|
+
...status,
|
|
1302
|
+
changed: false,
|
|
1303
|
+
written: false,
|
|
1304
|
+
};
|
|
1258
1305
|
}
|
|
1259
1306
|
await writeFile(file, content);
|
|
1260
1307
|
await chmod(file, 0o755).catch(() => {});
|
|
1308
|
+
return {
|
|
1309
|
+
...status,
|
|
1310
|
+
changed: true,
|
|
1311
|
+
written: true,
|
|
1312
|
+
reason: force && status.exists ? 'forced' : status.reason,
|
|
1313
|
+
previousHash: status.currentHash,
|
|
1314
|
+
currentHash: status.expectedHash,
|
|
1315
|
+
};
|
|
1261
1316
|
}
|
|
1262
1317
|
|
|
1263
1318
|
async function installCliShim(options = {}, env = process.env) {
|
|
@@ -1266,24 +1321,6 @@ async function installCliShim(options = {}, env = process.env) {
|
|
|
1266
1321
|
}
|
|
1267
1322
|
const existing = await existingDurableMagclawCommand('magclaw', env);
|
|
1268
1323
|
const existingComputer = await existingDurableMagclawCommand('magclaw-computer', env);
|
|
1269
|
-
const existingCommandsShareDir = Boolean(
|
|
1270
|
-
existing
|
|
1271
|
-
&& existingComputer
|
|
1272
|
-
&& path.dirname(existing) === path.dirname(existingComputer)
|
|
1273
|
-
);
|
|
1274
|
-
if (existingCommandsShareDir && !options.binDir && !options.cliBinDir && !options.force) {
|
|
1275
|
-
return {
|
|
1276
|
-
ok: true,
|
|
1277
|
-
command: 'magclaw',
|
|
1278
|
-
commands: ['magclaw', 'magclaw-computer'],
|
|
1279
|
-
installed: false,
|
|
1280
|
-
path: existing,
|
|
1281
|
-
files: [existing, existingComputer],
|
|
1282
|
-
pathReady: true,
|
|
1283
|
-
reason: 'already_available',
|
|
1284
|
-
};
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
1324
|
const target = (existing || existingComputer) && !options.binDir && !options.cliBinDir && !options.force
|
|
1288
1325
|
? { dir: path.dirname(existing || existingComputer), explicit: false, pathReady: true }
|
|
1289
1326
|
: await chooseCliShimBinDir(options, env);
|
|
@@ -1297,21 +1334,33 @@ async function installCliShim(options = {}, env = process.env) {
|
|
|
1297
1334
|
packageSpec,
|
|
1298
1335
|
computerPackageSpec,
|
|
1299
1336
|
});
|
|
1300
|
-
const
|
|
1337
|
+
const shimResults = [];
|
|
1301
1338
|
for (const shim of shimFiles) {
|
|
1302
1339
|
const file = path.join(target.dir, shim.name);
|
|
1303
|
-
await writeCliShimFile(file, shim.content, { force: Boolean(options.force) });
|
|
1304
|
-
|
|
1340
|
+
const result = await writeCliShimFile(file, shim.content, { force: Boolean(options.force) });
|
|
1341
|
+
shimResults.push({
|
|
1342
|
+
command: shim.command || shim.name,
|
|
1343
|
+
name: shim.name,
|
|
1344
|
+
...result,
|
|
1345
|
+
});
|
|
1305
1346
|
}
|
|
1347
|
+
const changedShims = shimResults.filter((shim) => shim.changed);
|
|
1348
|
+
const reason = changedShims.length
|
|
1349
|
+
? (changedShims.every((shim) => !shim.exists) ? 'installed' : 'updated')
|
|
1350
|
+
: 'already_current';
|
|
1306
1351
|
return {
|
|
1307
1352
|
ok: true,
|
|
1308
1353
|
command: 'magclaw',
|
|
1309
1354
|
commands: ['magclaw', 'magclaw-computer'],
|
|
1310
|
-
installed:
|
|
1355
|
+
installed: changedShims.length > 0,
|
|
1356
|
+
updated: changedShims.length > 0,
|
|
1311
1357
|
binDir: target.dir,
|
|
1312
|
-
files:
|
|
1313
|
-
|
|
1358
|
+
files: shimResults.map((shim) => shim.file),
|
|
1359
|
+
changedFiles: changedShims.map((shim) => shim.file),
|
|
1360
|
+
shims: shimResults,
|
|
1361
|
+
path: shimResults[0]?.file || '',
|
|
1314
1362
|
pathReady: Boolean(target.pathReady),
|
|
1363
|
+
reason,
|
|
1315
1364
|
packageSpec,
|
|
1316
1365
|
computerPackageSpec,
|
|
1317
1366
|
npmPath,
|