macca-method 2.1.2 → 2.1.3

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.2",
2
+ "version": "2.1.3",
3
3
  "skills": [
4
4
  "_shared",
5
5
  "add-feature",
@@ -164,6 +164,11 @@ function parseArgs(argv) {
164
164
  continue;
165
165
  }
166
166
 
167
+ if (token === "-f" || token === "--force") {
168
+ args.force = true;
169
+ continue;
170
+ }
171
+
167
172
  if (token === "--list-tools") {
168
173
  args.listTools = true;
169
174
  continue;
@@ -292,6 +297,7 @@ function printHelp() {
292
297
  " -t, --tool <name> Repeatable. Also accepts comma-separated values.",
293
298
  " -d, --directory <path> Target project directory. Defaults to the current directory.",
294
299
  " -y, --yes Skip prompts and use defaults where needed.",
300
+ " -f, --force Overwrite locally modified managed skills.",
295
301
  " --name <value> Developer name.",
296
302
  " --project <value> Project name.",
297
303
  " --communication-language <value>",
@@ -493,13 +499,37 @@ function hashText(content) {
493
499
  return crypto.createHash("sha256").update(content).digest("hex");
494
500
  }
495
501
 
502
+ const IGNORED_DIRECTORY_NAMES = new Set([
503
+ OWNERSHIP_MARKER,
504
+ ".DS_Store",
505
+ "Thumbs.db",
506
+ "__pycache__",
507
+ ".pytest_cache",
508
+ ".ruff_cache",
509
+ ]);
510
+
511
+ function shouldIgnoreDirectoryEntry(name) {
512
+ if (IGNORED_DIRECTORY_NAMES.has(name)) {
513
+ return true;
514
+ }
515
+ if (
516
+ name.endsWith(".pyc") ||
517
+ name.endsWith(".pyo") ||
518
+ name.endsWith(".tmp") ||
519
+ name.startsWith(".tmp-")
520
+ ) {
521
+ return true;
522
+ }
523
+ return false;
524
+ }
525
+
496
526
  function getDirectoryFileHashes(directoryPath) {
497
527
  const hashes = {};
498
528
 
499
529
  function walk(currentPath, relativePath = "") {
500
530
  const entries = fs
501
531
  .readdirSync(currentPath, { withFileTypes: true })
502
- .filter((entry) => entry.name !== OWNERSHIP_MARKER)
532
+ .filter((entry) => !shouldIgnoreDirectoryEntry(entry.name))
503
533
  .sort((left, right) => left.name.localeCompare(right.name));
504
534
 
505
535
  for (const entry of entries) {
@@ -648,7 +678,10 @@ function isMaccaOwned(targetPath) {
648
678
  return readOwnershipMarker(targetPath) !== null;
649
679
  }
650
680
 
651
- function assertManagedDirectoryUnchanged(targetPath) {
681
+ function assertManagedDirectoryUnchanged(targetPath, force = false) {
682
+ if (force) {
683
+ return;
684
+ }
652
685
  const marker = readOwnershipMarker(targetPath);
653
686
  if (!marker) {
654
687
  throw new Error(
@@ -657,7 +690,8 @@ function assertManagedDirectoryUnchanged(targetPath) {
657
690
  }
658
691
  if (!marker.payloadHash || marker.payloadHash !== hashDirectory(targetPath)) {
659
692
  throw new Error(
660
- `Refusing to overwrite locally modified managed skill: ${targetPath}`,
693
+ `Refusing to overwrite locally modified managed skill: ${targetPath}. ` +
694
+ "Run upgrade with --force to overwrite local modifications.",
661
695
  );
662
696
  }
663
697
  }
@@ -674,7 +708,10 @@ function readJsonObject(filePath, label) {
674
708
  }
675
709
  }
676
710
 
677
- function assertManagedFilesUnchanged(agentsDirectory) {
711
+ function assertManagedFilesUnchanged(agentsDirectory, force = false) {
712
+ if (force) {
713
+ return;
714
+ }
678
715
  const statePath = path.join(agentsDirectory, STATE_FILE);
679
716
  if (!fs.existsSync(statePath)) {
680
717
  return;
@@ -684,7 +721,8 @@ function assertManagedFilesUnchanged(agentsDirectory) {
684
721
  const filePath = path.join(agentsDirectory, fileName);
685
722
  if (!fs.existsSync(filePath) || hashFile(filePath) !== expectedHash) {
686
723
  throw new Error(
687
- `Refusing to overwrite locally modified MACCA metadata: ${filePath}`,
724
+ `Refusing to overwrite locally modified MACCA metadata: ${filePath}. ` +
725
+ "Run upgrade with --force to overwrite local modifications.",
688
726
  );
689
727
  }
690
728
  }
@@ -938,7 +976,7 @@ function getUniqueDestinations(targetDir, tools) {
938
976
  return [...destinations.values()];
939
977
  }
940
978
 
941
- function applySkillTransaction(entries, targetDir) {
979
+ function applySkillTransaction(entries, targetDir, force = false) {
942
980
  const suffix = `${process.pid}-${Date.now()}-${crypto.randomBytes(8).toString("hex")}`;
943
981
  const prepared = [];
944
982
  const committed = [];
@@ -971,7 +1009,7 @@ function applySkillTransaction(entries, targetDir) {
971
1009
  }
972
1010
  if (kind === "directory") {
973
1011
  if (isMaccaOwned(targetPath)) {
974
- assertManagedDirectoryUnchanged(targetPath);
1012
+ assertManagedDirectoryUnchanged(targetPath, force);
975
1013
  } else if (
976
1014
  !legacySkillName ||
977
1015
  !isLegacyDirectoryUnchanged(targetPath, legacySkillName)
@@ -1329,7 +1367,8 @@ async function promptForMetadata(seed) {
1329
1367
  }
1330
1368
  }
1331
1369
 
1332
- function applyInstall(targetDir, tools, metadata) {
1370
+ function applyInstall(targetDir, tools, metadata, options = {}) {
1371
+ const force = Boolean(options.force);
1333
1372
  const managedSkills = getSourceManagedSkills();
1334
1373
  const agentsDirectory = path.join(targetDir, ".agents");
1335
1374
  ensureDirectory(targetDir);
@@ -1344,7 +1383,7 @@ function applyInstall(targetDir, tools, metadata) {
1344
1383
  ]) {
1345
1384
  assertSafeProjectPath(targetDir, path.join(agentsDirectory, fileName));
1346
1385
  }
1347
- assertManagedFilesUnchanged(agentsDirectory);
1386
+ assertManagedFilesUnchanged(agentsDirectory, force);
1348
1387
  const previousManagedSkills = validateManagedSkillNames(
1349
1388
  readNonEmptyLines(path.join(agentsDirectory, "macca-managed-skills.txt")),
1350
1389
  ".agents/macca-managed-skills.txt",
@@ -1401,10 +1440,11 @@ function applyInstall(targetDir, tools, metadata) {
1401
1440
  targetPath: path.join(agentsDirectory, STATE_FILE),
1402
1441
  },
1403
1442
  );
1404
- applySkillTransaction(entries, targetDir);
1443
+ applySkillTransaction(entries, targetDir, force);
1405
1444
  }
1406
1445
 
1407
- function applyUpgrade(targetDir) {
1446
+ function applyUpgrade(targetDir, options = {}) {
1447
+ const force = Boolean(options.force);
1408
1448
  const agentsDirectory = path.join(targetDir, ".agents");
1409
1449
  assertSafeProjectPath(targetDir, agentsDirectory);
1410
1450
  assertPackageNotOlderThanInstalled(agentsDirectory);
@@ -1417,7 +1457,7 @@ function applyUpgrade(targetDir) {
1417
1457
  ]) {
1418
1458
  assertSafeProjectPath(targetDir, path.join(agentsDirectory, fileName));
1419
1459
  }
1420
- assertManagedFilesUnchanged(agentsDirectory);
1460
+ assertManagedFilesUnchanged(agentsDirectory, force);
1421
1461
  const tools = readNonEmptyLines(
1422
1462
  path.join(agentsDirectory, "macca-tools.txt"),
1423
1463
  );
@@ -1447,7 +1487,7 @@ function applyUpgrade(targetDir) {
1447
1487
  )) {
1448
1488
  const oldPath = resolveOwnedSkillPath(destination, skillName);
1449
1489
  if (fs.existsSync(oldPath) && isMaccaOwned(oldPath)) {
1450
- assertManagedDirectoryUnchanged(oldPath);
1490
+ assertManagedDirectoryUnchanged(oldPath, force);
1451
1491
  entries.push({ sourcePath: null, targetPath: oldPath });
1452
1492
  } else if (isLegacyDirectoryUnchanged(oldPath, skillName)) {
1453
1493
  entries.push({
@@ -1469,7 +1509,7 @@ function applyUpgrade(targetDir) {
1469
1509
  for (const skillName of previousManagedSkills) {
1470
1510
  const oldPath = resolveOwnedSkillPath(legacyOpenCodeRoot, skillName);
1471
1511
  if (fs.existsSync(oldPath) && isMaccaOwned(oldPath)) {
1472
- assertManagedDirectoryUnchanged(oldPath);
1512
+ assertManagedDirectoryUnchanged(oldPath, force);
1473
1513
  entries.push({ sourcePath: null, targetPath: oldPath });
1474
1514
  } else if (isLegacyDirectoryUnchanged(oldPath, skillName)) {
1475
1515
  entries.push({
@@ -1478,9 +1518,12 @@ function applyUpgrade(targetDir) {
1478
1518
  legacySkillName: skillName,
1479
1519
  });
1480
1520
  } else if (fs.existsSync(oldPath)) {
1481
- throw new Error(
1482
- `Legacy OpenCode skill was modified; move or back it up before upgrade: ${oldPath}`,
1483
- );
1521
+ if (!force) {
1522
+ throw new Error(
1523
+ `Legacy OpenCode skill was modified; move or back it up before upgrade: ${oldPath}. ` +
1524
+ "Run upgrade with --force to overwrite local modifications.",
1525
+ );
1526
+ }
1484
1527
  }
1485
1528
  }
1486
1529
  }
@@ -1511,7 +1554,7 @@ function applyUpgrade(targetDir) {
1511
1554
  targetPath: path.join(agentsDirectory, STATE_FILE),
1512
1555
  },
1513
1556
  );
1514
- applySkillTransaction(entries, targetDir);
1557
+ applySkillTransaction(entries, targetDir, force);
1515
1558
 
1516
1559
  if (tools.includes("kimi")) reportLegacyKimiInstall();
1517
1560
  }
@@ -1620,7 +1663,7 @@ async function runInstall(args) {
1620
1663
  : existingConfig.languagePreferences?.documents?.raw,
1621
1664
  });
1622
1665
 
1623
- applyInstall(targetDir, tools, metadata);
1666
+ applyInstall(targetDir, tools, metadata, { force: Boolean(args.force) });
1624
1667
 
1625
1668
  printInstallSummary("installed", tools);
1626
1669
  process.stdout.write(` Target project: ${targetDir}\n\n`);
@@ -1633,7 +1676,7 @@ function runUpgrade(args) {
1633
1676
  const tools = readNonEmptyLines(
1634
1677
  path.join(targetDir, ".agents", "macca-tools.txt"),
1635
1678
  );
1636
- applyUpgrade(targetDir);
1679
+ applyUpgrade(targetDir, { force: Boolean(args.force) });
1637
1680
  printInstallSummary("updated", tools);
1638
1681
  process.stdout.write(` Target project: ${targetDir}\n\n`);
1639
1682
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "macca-method",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "CLI installer for MACCA AI spec-driven development skills.",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -77,7 +77,7 @@ function runCli(args) {
77
77
  "exec",
78
78
  "--yes",
79
79
  "--package",
80
- "macca-method",
80
+ "macca-method@latest",
81
81
  "--",
82
82
  "macca-method",
83
83
  ...args,
@@ -104,7 +104,7 @@ function expectCliFailure(args, expectedText) {
104
104
  "exec",
105
105
  "--yes",
106
106
  "--package",
107
- "macca-method",
107
+ "macca-method@latest",
108
108
  "--",
109
109
  "macca-method",
110
110
  ...args,
@@ -509,6 +509,7 @@ function main() {
509
509
  ["upgrade", "--directory", driftDir],
510
510
  "locally modified managed skill",
511
511
  );
512
+ runCli(["upgrade", "--directory", driftDir, "--force"]);
512
513
 
513
514
  assertPathExists(path.join(projectDir, ".agents", "developer-config.json"));
514
515
  assertPathExists(