atris 3.68.8 → 3.68.9
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/commands/sync.js +41 -3
- package/package.json +1 -1
package/commands/sync.js
CHANGED
|
@@ -83,6 +83,23 @@ function ensureRealDirectory(dir) {
|
|
|
83
83
|
fs.mkdirSync(dir, { recursive: true });
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// A hook script the project already has is never replaced. Projects harden
|
|
87
|
+
// their hooks (nonce checks, queues, proof before pop); a sync must not
|
|
88
|
+
// downgrade them to the shipped copy.
|
|
89
|
+
function isProtectedHook(destPath) {
|
|
90
|
+
return path.basename(path.dirname(destPath)) === 'hooks' && fs.existsSync(destPath);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A member retired to team/_archived/<name>-<date>/ must never come back.
|
|
94
|
+
function isArchivedMember(teamDir, name) {
|
|
95
|
+
const archiveDir = path.join(teamDir, '_archived');
|
|
96
|
+
try {
|
|
97
|
+
return fs.readdirSync(archiveDir).some(entry => entry === name || (entry.startsWith(`${name}-`) && /^\d{4}-\d{2}-\d{2}$/.test(entry.slice(name.length + 1))));
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
86
103
|
/**
|
|
87
104
|
* Sync the canonical skill set from atris-cli/atris/skills/* into a
|
|
88
105
|
* workspace's atris/skills/* (plus ensure .claude/skills/ symlinks).
|
|
@@ -128,7 +145,9 @@ function syncPackageSkills(targetAtrisDir, opts = {}) {
|
|
|
128
145
|
} else {
|
|
129
146
|
const srcContent = fs.readFileSync(srcPath, 'utf8');
|
|
130
147
|
const destContent = fs.existsSync(destPath) ? fs.readFileSync(destPath, 'utf8') : '';
|
|
131
|
-
if (srcContent !== destContent) {
|
|
148
|
+
if (srcContent !== destContent && isProtectedHook(destPath)) {
|
|
149
|
+
if (verbose) console.log(`- Kept atris/skills/${skillName}/${relPath} (differs from shipped hook, not replaced)`);
|
|
150
|
+
} else if (srcContent !== destContent) {
|
|
132
151
|
if (!dryRun) {
|
|
133
152
|
fs.writeFileSync(destPath, srcContent);
|
|
134
153
|
if (entry.endsWith('.sh')) fs.chmodSync(destPath, 0o755);
|
|
@@ -348,6 +367,12 @@ function syncWorkspaceTemplate(targetRoot, bizMeta, options = {}) {
|
|
|
348
367
|
try { templateContent = fs.readFileSync(templatePath, 'utf-8'); } catch { continue; }
|
|
349
368
|
const finalContent = _substituteParams(templateContent, params);
|
|
350
369
|
|
|
370
|
+
const memberMatch = targetRelPath.split(path.sep).join('/').match(/^team\/([^/_][^/]*)\//);
|
|
371
|
+
if (memberMatch && isArchivedMember(path.join(targetAtrisDir, 'team'), memberMatch[1])) {
|
|
372
|
+
skipped++;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
|
|
351
376
|
if (!fs.existsSync(targetPath)) {
|
|
352
377
|
addedList.push(targetRelPath); added++;
|
|
353
378
|
if (!dryRun) {
|
|
@@ -358,7 +383,7 @@ function syncWorkspaceTemplate(targetRoot, bizMeta, options = {}) {
|
|
|
358
383
|
const existing = fs.readFileSync(targetPath, 'utf-8');
|
|
359
384
|
if (existing === finalContent) {
|
|
360
385
|
skipped++;
|
|
361
|
-
} else if (force) {
|
|
386
|
+
} else if (force && !memberMatch) {
|
|
362
387
|
updatedList.push(targetRelPath); updated++;
|
|
363
388
|
if (!dryRun) fs.writeFileSync(targetPath, finalContent);
|
|
364
389
|
} else {
|
|
@@ -565,6 +590,17 @@ function syncAtris(options = {}) {
|
|
|
565
590
|
return;
|
|
566
591
|
}
|
|
567
592
|
|
|
593
|
+
// Team members belong to the project. Update never adds a member (init
|
|
594
|
+
// does that, and a missing member may have been retired to
|
|
595
|
+
// team/_archived/) and never replaces one the project has changed.
|
|
596
|
+
if (target.startsWith('team/')) {
|
|
597
|
+
if (fs.existsSync(targetFile)) {
|
|
598
|
+
console.log(`- Kept ${target} (newer template exists in the package, yours not replaced)`);
|
|
599
|
+
}
|
|
600
|
+
skipped++;
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
|
|
568
604
|
if (!dryRun) {
|
|
569
605
|
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
570
606
|
fs.copyFileSync(sourceFile, targetFile);
|
|
@@ -728,7 +764,9 @@ function syncRecursiveCount(src, dest, label, silent) {
|
|
|
728
764
|
} else {
|
|
729
765
|
const srcBuf = fs.readFileSync(srcPath);
|
|
730
766
|
const destBuf = fs.existsSync(destPath) ? fs.readFileSync(destPath) : Buffer.alloc(0);
|
|
731
|
-
if (!srcBuf.equals(destBuf)) {
|
|
767
|
+
if (!srcBuf.equals(destBuf) && isProtectedHook(destPath)) {
|
|
768
|
+
if (!silent) console.log(`- Kept ${label}/${entry} (differs from shipped hook, not replaced)`);
|
|
769
|
+
} else if (!srcBuf.equals(destBuf)) {
|
|
732
770
|
fs.writeFileSync(destPath, srcBuf);
|
|
733
771
|
if (entry.endsWith('.sh')) {
|
|
734
772
|
fs.chmodSync(destPath, 0o755);
|