claude-comms 2.0.19 → 2.0.21
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/fetcher/github.js +26 -0
- package/src/orchestrator/installer.js +73 -4
package/package.json
CHANGED
package/src/fetcher/github.js
CHANGED
|
@@ -211,6 +211,32 @@ class GitHubFetcher extends EventEmitter {
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Resolve a Git ref to the full commit SHA, best-effort.
|
|
216
|
+
* @param {string} ref - Branch, tag, or commit ref
|
|
217
|
+
* @returns {Promise<string|null>} Full commit SHA or null when unavailable
|
|
218
|
+
*/
|
|
219
|
+
async resolveCommitSha(ref) {
|
|
220
|
+
const commitRef = ref || this.repository.branch;
|
|
221
|
+
const encodedRef = encodeURIComponent(commitRef);
|
|
222
|
+
const url = `${this.config.baseUrl}/repos/${this.repository.owner}/${this.repository.repo}/commits/${encodedRef}`;
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const response = await this._makeRequest(url);
|
|
226
|
+
const data = await response.json();
|
|
227
|
+
|
|
228
|
+
if (data && typeof data.sha === 'string' && data.sha.length > 0) {
|
|
229
|
+
return data.sha;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.warn(`Unable to resolve commit SHA for ${commitRef}: response did not include sha`);
|
|
233
|
+
return null;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.warn(`Unable to resolve commit SHA for ${commitRef}: ${error.message}`);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
214
240
|
/**
|
|
215
241
|
* Strategy 1: GitHub Trees API for recursive directory fetch
|
|
216
242
|
* @private
|
|
@@ -16,6 +16,9 @@ const EventEmitter = require('events');
|
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const { InstallerError } = require('../utils/errors');
|
|
18
18
|
const { ROOT_FILES } = require('../utils/constants');
|
|
19
|
+
const { version: ENGINE_VERSION } = require('../../package.json');
|
|
20
|
+
|
|
21
|
+
const ENGINE_MANIFEST_PATH = '.agents/engine-manifest.json';
|
|
19
22
|
|
|
20
23
|
// Error codes enum - matches interface contracts
|
|
21
24
|
const ErrorCode = {
|
|
@@ -317,9 +320,12 @@ class Installer extends EventEmitter {
|
|
|
317
320
|
this.state = InstallationState.WRITING;
|
|
318
321
|
this._emitProgress('Installing files...', 50);
|
|
319
322
|
|
|
323
|
+
const flattenedFiles = this._flattenFiles(fetchedFiles);
|
|
324
|
+
const filesWithManifest = await this._appendEngineManifest(flattenedFiles);
|
|
325
|
+
|
|
320
326
|
if (this.options.dryRun) {
|
|
321
327
|
this.logger.info('DRY RUN: Would install files to:', this.options.targetDir);
|
|
322
|
-
this._simulateInstallation(
|
|
328
|
+
this._simulateInstallation(filesWithManifest);
|
|
323
329
|
return;
|
|
324
330
|
}
|
|
325
331
|
|
|
@@ -337,7 +343,7 @@ class Installer extends EventEmitter {
|
|
|
337
343
|
await this._createBackupsIfNeeded(fetchedFiles);
|
|
338
344
|
|
|
339
345
|
// Flatten files and filter out user-customizable files if they already exist
|
|
340
|
-
let filesToWrite =
|
|
346
|
+
let filesToWrite = filesWithManifest;
|
|
341
347
|
|
|
342
348
|
// Files that should not be overwritten if they exist (user customizations)
|
|
343
349
|
const preserveIfExists = [
|
|
@@ -657,13 +663,76 @@ class Installer extends EventEmitter {
|
|
|
657
663
|
return flattened;
|
|
658
664
|
}
|
|
659
665
|
|
|
666
|
+
/**
|
|
667
|
+
* Append the synthetic engine manifest to the normal write set.
|
|
668
|
+
*/
|
|
669
|
+
async _appendEngineManifest(filesToWrite) {
|
|
670
|
+
const engineGitSha = await this._resolveEngineGitSha(this.options.version);
|
|
671
|
+
const withoutManifest = filesToWrite.filter(file => file.path !== ENGINE_MANIFEST_PATH);
|
|
672
|
+
|
|
673
|
+
return [
|
|
674
|
+
...withoutManifest,
|
|
675
|
+
this._createEngineManifestFile(engineGitSha)
|
|
676
|
+
];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Resolve the fetched ref to a commit SHA without blocking installation.
|
|
681
|
+
*/
|
|
682
|
+
async _resolveEngineGitSha(ref) {
|
|
683
|
+
if (!this.fetcher || typeof this.fetcher.resolveCommitSha !== 'function') {
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
try {
|
|
688
|
+
return await this.fetcher.resolveCommitSha(ref);
|
|
689
|
+
} catch (error) {
|
|
690
|
+
this.logger.warn(`Unable to resolve engine commit SHA: ${error.message}`);
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Create the manifest file stamped into installed .agents copies.
|
|
697
|
+
*/
|
|
698
|
+
_createEngineManifestFile(engineGitSha) {
|
|
699
|
+
const ref = this.options.version;
|
|
700
|
+
const manifest = {
|
|
701
|
+
engineVersion: ENGINE_VERSION,
|
|
702
|
+
engineGitSha: typeof engineGitSha === 'string' ? engineGitSha : null,
|
|
703
|
+
installedFrom: `${this._getRepositorySlug()}#${ref}`,
|
|
704
|
+
installedAt: new Date().toISOString()
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
return {
|
|
708
|
+
path: ENGINE_MANIFEST_PATH,
|
|
709
|
+
content: JSON.stringify(manifest, null, 2),
|
|
710
|
+
encoding: 'utf-8'
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Repository identity used in the install manifest.
|
|
716
|
+
*/
|
|
717
|
+
_getRepositorySlug() {
|
|
718
|
+
const repository = this.fetcher && this.fetcher.repository;
|
|
719
|
+
const owner = repository && repository.owner;
|
|
720
|
+
const repo = repository && (repository.repo || repository.name);
|
|
721
|
+
|
|
722
|
+
if (owner && repo) {
|
|
723
|
+
return `${owner}/${repo}`;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return 'unknown/unknown';
|
|
727
|
+
}
|
|
728
|
+
|
|
660
729
|
/**
|
|
661
730
|
* Simulate installation for dry-run mode
|
|
662
731
|
*/
|
|
663
|
-
_simulateInstallation(
|
|
732
|
+
_simulateInstallation(filesToWrite) {
|
|
664
733
|
this.logger.info('DRY RUN: Files that would be installed:');
|
|
665
734
|
|
|
666
|
-
const flattened = this._flattenFiles(
|
|
735
|
+
const flattened = Array.isArray(filesToWrite) ? filesToWrite : this._flattenFiles(filesToWrite);
|
|
667
736
|
flattened.forEach(file => {
|
|
668
737
|
const targetPath = path.join(this.options.targetDir, file.path);
|
|
669
738
|
this.logger.info(` • ${targetPath}`);
|