fraim-framework 2.0.33 → 2.0.35

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/bin/fraim.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * FRAIM CLI Entry Point
5
+ * This wrapper loads and executes the compiled CLI from dist/
6
+ */
7
+
8
+ require('../dist/src/cli/fraim.js');
@@ -60,97 +60,92 @@ const runSync = async (options) => {
60
60
  const existingDigest = fs_1.default.existsSync(digestPath) ? fs_1.default.readFileSync(digestPath, 'utf8') : '';
61
61
  if (currentDigest === existingDigest && !options.force) {
62
62
  console.log(chalk_1.default.green('✅ Workflows are already in sync.'));
63
- return;
64
63
  }
65
- const registryWorkflowsPath = path_1.default.join(registryPath, 'workflows');
66
- if (!fs_1.default.existsSync(registryWorkflowsPath)) {
67
- console.log(chalk_1.default.yellow('⚠️ No workflows found in registry.'));
68
- return;
69
- }
70
- // Get all workflows from registry (recursive)
71
- const getFiles = (dir) => {
72
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
73
- const files = entries
74
- .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
75
- .map(e => path_1.default.join(dir, e.name));
76
- const folders = entries.filter(e => e.isDirectory());
77
- for (const folder of folders) {
78
- files.push(...getFiles(path_1.default.join(dir, folder.name)));
79
- }
80
- return files;
81
- };
82
- const registryFiles = getFiles(registryWorkflowsPath);
83
- const generatedStubs = [];
84
- for (const file of registryFiles) {
85
- const content = fs_1.default.readFileSync(file, 'utf8');
86
- const { intent, principles } = (0, stub_generator_1.parseRegistryWorkflow)(content);
87
- const fileName = path_1.default.basename(file);
88
- const workflowName = fileName.replace('.md', '');
89
- // Calculate relative path from registry/workflows to preserve structure
90
- const relativePath = path_1.default.relative(registryWorkflowsPath, file);
91
- const relativeDir = path_1.default.dirname(relativePath);
92
- // Ensure target directory exists
93
- const targetDir = path_1.default.join(workflowsDir, relativeDir);
94
- if (!fs_1.default.existsSync(targetDir)) {
95
- fs_1.default.mkdirSync(targetDir, { recursive: true });
96
- }
97
- const stubContent = (0, stub_generator_1.generateWorkflowStub)(workflowName, file, intent, principles);
98
- const stubPath = path_1.default.join(targetDir, fileName);
99
- fs_1.default.writeFileSync(stubPath, stubContent);
100
- generatedStubs.push(relativePath); // Store relative path for cleanup tracking
101
- console.log(chalk_1.default.gray(` + ${workflowName} (${relativeDir === '.' ? 'root' : relativeDir})`));
102
- }
103
- // Cleanup stubs that no longer exist in registry
104
- // Cleanup stubs that no longer exist in registry
105
- // Helper to get all local stubs recursively
106
- const getLocalStubs = (dir) => {
107
- if (!fs_1.default.existsSync(dir))
108
- return [];
109
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
110
- const files = entries
111
- .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
112
- .map(e => path_1.default.relative(workflowsDir, path_1.default.join(dir, e.name)));
113
- const folders = entries.filter(e => e.isDirectory());
114
- for (const folder of folders) {
115
- files.push(...getLocalStubs(path_1.default.join(dir, folder.name)));
64
+ else {
65
+ const registryWorkflowsPath = path_1.default.join(registryPath, 'workflows');
66
+ if (!fs_1.default.existsSync(registryWorkflowsPath)) {
67
+ console.log(chalk_1.default.yellow('⚠️ No workflows found in registry.'));
116
68
  }
117
- return files;
118
- };
119
- const localStubs = getLocalStubs(workflowsDir);
120
- for (const stub of localStubs) {
121
- // standardise path separators for comparison
122
- const normalizedStub = stub.replace(/\\/g, '/');
123
- const normalizedGenerated = generatedStubs.map(s => s.replace(/\\/g, '/'));
124
- if (!normalizedGenerated.includes(normalizedStub)) {
125
- fs_1.default.unlinkSync(path_1.default.join(workflowsDir, stub));
126
- console.log(chalk_1.default.yellow(` - ${stub} (removed from registry)`));
127
- // Cleanup empty directories
128
- try {
129
- const dir = path_1.default.dirname(path_1.default.join(workflowsDir, stub));
130
- if (fs_1.default.readdirSync(dir).length === 0) {
131
- fs_1.default.rmdirSync(dir);
69
+ else {
70
+ // Get all workflows from registry (recursive)
71
+ const getFiles = (dir) => {
72
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
73
+ const files = entries
74
+ .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
75
+ .map(e => path_1.default.join(dir, e.name));
76
+ const folders = entries.filter(e => e.isDirectory());
77
+ for (const folder of folders) {
78
+ files.push(...getFiles(path_1.default.join(dir, folder.name)));
79
+ }
80
+ return files;
81
+ };
82
+ const registryFiles = getFiles(registryWorkflowsPath);
83
+ const generatedStubs = [];
84
+ for (const file of registryFiles) {
85
+ const content = fs_1.default.readFileSync(file, 'utf8');
86
+ const { intent, principles } = (0, stub_generator_1.parseRegistryWorkflow)(content);
87
+ const fileName = path_1.default.basename(file);
88
+ const workflowName = fileName.replace('.md', '');
89
+ // Calculate relative path from registry/workflows to preserve structure
90
+ const relativePath = path_1.default.relative(registryWorkflowsPath, file);
91
+ const relativeDir = path_1.default.dirname(relativePath);
92
+ // Ensure target directory exists
93
+ const targetDir = path_1.default.join(workflowsDir, relativeDir);
94
+ if (!fs_1.default.existsSync(targetDir)) {
95
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
132
96
  }
97
+ const stubContent = (0, stub_generator_1.generateWorkflowStub)(workflowName, file, intent, principles);
98
+ const stubPath = path_1.default.join(targetDir, fileName);
99
+ fs_1.default.writeFileSync(stubPath, stubContent);
100
+ generatedStubs.push(relativePath); // Store relative path for cleanup tracking
101
+ console.log(chalk_1.default.gray(` + ${workflowName} (${relativeDir === '.' ? 'root' : relativeDir})`));
133
102
  }
134
- catch (e) { }
103
+ // Cleanup stubs that no longer exist in registry
104
+ // Helper to get all local stubs recursively
105
+ const getLocalStubs = (dir) => {
106
+ if (!fs_1.default.existsSync(dir))
107
+ return [];
108
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
109
+ const files = entries
110
+ .filter(e => !e.isDirectory() && e.name.endsWith('.md'))
111
+ .map(e => path_1.default.relative(workflowsDir, path_1.default.join(dir, e.name)));
112
+ const folders = entries.filter(e => e.isDirectory());
113
+ for (const folder of folders) {
114
+ files.push(...getLocalStubs(path_1.default.join(dir, folder.name)));
115
+ }
116
+ return files;
117
+ };
118
+ const localStubs = getLocalStubs(workflowsDir);
119
+ for (const stub of localStubs) {
120
+ // standardise path separators for comparison
121
+ const normalizedStub = stub.replace(/\\/g, '/');
122
+ const normalizedGenerated = generatedStubs.map(s => s.replace(/\\/g, '/'));
123
+ if (!normalizedGenerated.includes(normalizedStub)) {
124
+ fs_1.default.unlinkSync(path_1.default.join(workflowsDir, stub));
125
+ console.log(chalk_1.default.yellow(` - ${stub} (removed from registry)`));
126
+ // Cleanup empty directories
127
+ try {
128
+ const dir = path_1.default.dirname(path_1.default.join(workflowsDir, stub));
129
+ if (fs_1.default.readdirSync(dir).length === 0) {
130
+ fs_1.default.rmdirSync(dir);
131
+ }
132
+ }
133
+ catch (e) { }
134
+ }
135
+ }
136
+ fs_1.default.writeFileSync(digestPath, currentDigest);
137
+ console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Generated ${generatedStubs.length} stubs.`));
135
138
  }
136
139
  }
137
- fs_1.default.writeFileSync(digestPath, currentDigest);
138
- console.log(chalk_1.default.green(`\n✅ Workflow sync complete. Generated ${generatedStubs.length} stubs.`));
139
- // Sync scripts to user directory
140
+ // Always sync scripts, regardless of workflow sync status
140
141
  console.log(chalk_1.default.blue('\n🔄 Syncing FRAIM scripts to user directory...'));
141
142
  const syncResult = (0, script_sync_utils_1.syncScriptsToUserDirectory)(registryPath);
142
143
  const cleanedScriptCount = (0, script_sync_utils_1.cleanupObsoleteUserScripts)(registryPath);
143
144
  if (syncResult.synced > 0 || cleanedScriptCount > 0) {
144
- console.log(chalk_1.default.green(`✅ Script sync complete. Updated ${syncResult.synced} self-contained scripts, removed ${cleanedScriptCount} obsolete scripts.`));
145
- if (syncResult.ephemeral > 0) {
146
- console.log(chalk_1.default.gray(` ${syncResult.ephemeral} dependent scripts will use ephemeral execution.`));
147
- }
145
+ console.log(chalk_1.default.green(`✅ Script sync complete. Updated ${syncResult.synced} scripts, removed ${cleanedScriptCount} obsolete scripts.`));
148
146
  }
149
147
  else {
150
148
  console.log(chalk_1.default.green('✅ Scripts are already in sync.'));
151
- if (syncResult.ephemeral > 0) {
152
- console.log(chalk_1.default.gray(` ${syncResult.ephemeral} dependent scripts will use ephemeral execution.`));
153
- }
154
149
  }
155
150
  };
156
151
  exports.runSync = runSync;
@@ -6,14 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getUserFraimDir = getUserFraimDir;
7
7
  exports.getUserScriptsDir = getUserScriptsDir;
8
8
  exports.ensureUserFraimDirectories = ensureUserFraimDirectories;
9
- exports.isScriptSelfContained = isScriptSelfContained;
10
9
  exports.getRegistryScripts = getRegistryScripts;
11
10
  exports.copyScriptToUserDirectory = copyScriptToUserDirectory;
12
11
  exports.syncScriptsToUserDirectory = syncScriptsToUserDirectory;
13
12
  exports.cleanupObsoleteUserScripts = cleanupObsoleteUserScripts;
14
13
  exports.getUserScriptPath = getUserScriptPath;
15
14
  exports.userScriptExists = userScriptExists;
16
- exports.getDependentRegistryScripts = getDependentRegistryScripts;
17
15
  exports.validateUserScripts = validateUserScripts;
18
16
  const fs_1 = __importDefault(require("fs"));
19
17
  const path_1 = __importDefault(require("path"));
@@ -46,60 +44,54 @@ function ensureUserFraimDirectories() {
46
44
  }
47
45
  }
48
46
  /**
49
- * Check if a script is self-contained (no relative imports to FRAIM source)
50
- */
51
- function isScriptSelfContained(scriptPath) {
52
- // Shell scripts are always considered self-contained
53
- if (scriptPath.endsWith('.sh')) {
54
- return true;
55
- }
56
- // For TypeScript/JavaScript files, check for relative imports to src/
57
- if (scriptPath.endsWith('.ts') || scriptPath.endsWith('.js')) {
58
- try {
59
- const content = fs_1.default.readFileSync(scriptPath, 'utf-8');
60
- // Look for imports that reference ../../src/ or similar patterns
61
- const hasRelativeImports = /import.*['"]\.\.\/.*src\//.test(content) ||
62
- /require\(['"]\.\.\/.*src\//.test(content) ||
63
- /from ['"]\.\.\/.*src\//.test(content);
64
- return !hasRelativeImports;
65
- }
66
- catch (error) {
67
- // If we can't read the file, assume it's not self-contained
68
- return false;
69
- }
70
- }
71
- return false;
72
- }
73
- /**
74
- * Get all self-contained script files from the registry
47
+ * Get all script files from the registry (recursively)
75
48
  */
76
49
  function getRegistryScripts(registryPath) {
77
50
  const scriptsPath = path_1.default.join(registryPath, 'scripts');
78
51
  if (!fs_1.default.existsSync(scriptsPath)) {
79
52
  return [];
80
53
  }
81
- const entries = fs_1.default.readdirSync(scriptsPath, { withFileTypes: true });
82
- const allScripts = entries
83
- .filter(entry => entry.isFile() && (entry.name.endsWith('.sh') || entry.name.endsWith('.ts') || entry.name.endsWith('.js')))
84
- .map(entry => path_1.default.join(scriptsPath, entry.name));
85
- // Only return self-contained scripts
86
- return allScripts.filter(scriptPath => isScriptSelfContained(scriptPath));
54
+ const getAllFiles = (dir, baseDir = dir) => {
55
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
56
+ let files = [];
57
+ for (const entry of entries) {
58
+ const fullPath = path_1.default.join(dir, entry.name);
59
+ if (entry.isDirectory()) {
60
+ // Recursively get files from subdirectories
61
+ files = files.concat(getAllFiles(fullPath, baseDir));
62
+ }
63
+ else {
64
+ // Include all files (not just specific extensions)
65
+ files.push(fullPath);
66
+ }
67
+ }
68
+ return files;
69
+ };
70
+ return getAllFiles(scriptsPath);
87
71
  }
88
72
  /**
89
73
  * Copy a script file to the user scripts directory with proper permissions
74
+ * Preserves directory structure from registry/scripts/
90
75
  */
91
- function copyScriptToUserDirectory(sourcePath, scriptName) {
76
+ function copyScriptToUserDirectory(sourcePath, registryScriptsPath) {
92
77
  const userScriptsDir = getUserScriptsDir();
93
- const targetPath = path_1.default.join(userScriptsDir, scriptName);
78
+ // Calculate relative path from registry/scripts to preserve structure
79
+ const relativePath = path_1.default.relative(registryScriptsPath, sourcePath);
80
+ const targetPath = path_1.default.join(userScriptsDir, relativePath);
81
+ // Ensure target directory exists
82
+ const targetDir = path_1.default.dirname(targetPath);
83
+ if (!fs_1.default.existsSync(targetDir)) {
84
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
85
+ }
94
86
  // Copy the file
95
87
  fs_1.default.copyFileSync(sourcePath, targetPath);
96
- // Set executable permissions on Unix systems
97
- if (process.platform !== 'win32' && scriptName.endsWith('.sh')) {
88
+ // Set executable permissions on Unix systems for shell scripts
89
+ if (process.platform !== 'win32' && sourcePath.endsWith('.sh')) {
98
90
  try {
99
91
  fs_1.default.chmodSync(targetPath, 0o755);
100
92
  }
101
93
  catch (error) {
102
- console.warn(chalk_1.default.yellow(`⚠️ Could not set executable permissions for ${scriptName}`));
94
+ console.warn(chalk_1.default.yellow(`⚠️ Could not set executable permissions for ${relativePath}`));
103
95
  }
104
96
  }
105
97
  }
@@ -108,13 +100,13 @@ function copyScriptToUserDirectory(sourcePath, scriptName) {
108
100
  */
109
101
  function syncScriptsToUserDirectory(registryPath) {
110
102
  ensureUserFraimDirectories();
111
- const selfContainedScripts = getRegistryScripts(registryPath);
112
- const dependentScripts = getDependentRegistryScripts(registryPath);
103
+ const registryScriptsPath = path_1.default.join(registryPath, 'scripts');
104
+ const allScripts = getRegistryScripts(registryPath);
113
105
  let syncedCount = 0;
114
- console.log(chalk_1.default.gray(` Self-contained scripts (will be synced to ~/.fraim/scripts/):`));
115
- for (const scriptPath of selfContainedScripts) {
116
- const scriptName = path_1.default.basename(scriptPath);
117
- const userScriptPath = path_1.default.join(getUserScriptsDir(), scriptName);
106
+ console.log(chalk_1.default.gray(` Syncing all scripts to ~/.fraim/scripts/:`));
107
+ for (const scriptPath of allScripts) {
108
+ const relativePath = path_1.default.relative(registryScriptsPath, scriptPath);
109
+ const userScriptPath = path_1.default.join(getUserScriptsDir(), relativePath);
118
110
  try {
119
111
  // Check if script needs updating
120
112
  let needsUpdate = true;
@@ -124,26 +116,19 @@ function syncScriptsToUserDirectory(registryPath) {
124
116
  needsUpdate = registryContent !== userContent;
125
117
  }
126
118
  if (needsUpdate) {
127
- copyScriptToUserDirectory(scriptPath, scriptName);
119
+ copyScriptToUserDirectory(scriptPath, registryScriptsPath);
128
120
  syncedCount++;
129
- console.log(chalk_1.default.gray(` + ${scriptName}`));
121
+ console.log(chalk_1.default.gray(` + ${relativePath}`));
130
122
  }
131
123
  else {
132
- console.log(chalk_1.default.gray(` = ${scriptName} (up to date)`));
124
+ console.log(chalk_1.default.gray(` = ${relativePath} (up to date)`));
133
125
  }
134
126
  }
135
127
  catch (error) {
136
- console.warn(chalk_1.default.yellow(`⚠️ Could not sync script ${scriptName}: ${error}`));
128
+ console.warn(chalk_1.default.yellow(`⚠️ Could not sync script ${relativePath}: ${error}`));
137
129
  }
138
130
  }
139
- if (dependentScripts.length > 0) {
140
- console.log(chalk_1.default.gray(` Dependent scripts (will use ephemeral execution):`));
141
- for (const scriptPath of dependentScripts) {
142
- const scriptName = path_1.default.basename(scriptPath);
143
- console.log(chalk_1.default.gray(` ~ ${scriptName} (has FRAIM dependencies)`));
144
- }
145
- }
146
- return { synced: syncedCount, ephemeral: dependentScripts.length };
131
+ return { synced: syncedCount, ephemeral: 0 };
147
132
  }
148
133
  /**
149
134
  * Clean up scripts in user directory that no longer exist in registry
@@ -153,21 +138,49 @@ function cleanupObsoleteUserScripts(registryPath) {
153
138
  if (!fs_1.default.existsSync(userScriptsDir)) {
154
139
  return 0;
155
140
  }
141
+ const registryScriptsPath = path_1.default.join(registryPath, 'scripts');
156
142
  const registryScripts = getRegistryScripts(registryPath);
157
- const registryScriptNames = registryScripts.map(scriptPath => path_1.default.basename(scriptPath));
158
- const userScripts = fs_1.default.readdirSync(userScriptsDir)
159
- .filter(file => file.endsWith('.sh') || file.endsWith('.ts') || file.endsWith('.js'));
143
+ const registryRelativePaths = registryScripts.map(scriptPath => path_1.default.relative(registryScriptsPath, scriptPath));
144
+ // Get all files in user scripts directory recursively
145
+ const getAllUserFiles = (dir, baseDir = dir) => {
146
+ if (!fs_1.default.existsSync(dir))
147
+ return [];
148
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
149
+ let files = [];
150
+ for (const entry of entries) {
151
+ const fullPath = path_1.default.join(dir, entry.name);
152
+ if (entry.isDirectory()) {
153
+ files = files.concat(getAllUserFiles(fullPath, baseDir));
154
+ }
155
+ else {
156
+ files.push(path_1.default.relative(baseDir, fullPath));
157
+ }
158
+ }
159
+ return files;
160
+ };
161
+ const userFiles = getAllUserFiles(userScriptsDir);
160
162
  let cleanedCount = 0;
161
- for (const userScript of userScripts) {
162
- if (!registryScriptNames.includes(userScript)) {
163
+ for (const userFile of userFiles) {
164
+ // Normalize path separators for comparison
165
+ const normalizedUserFile = userFile.replace(/\\/g, '/');
166
+ const normalizedRegistry = registryRelativePaths.map(p => p.replace(/\\/g, '/'));
167
+ if (!normalizedRegistry.includes(normalizedUserFile)) {
163
168
  try {
164
- const userScriptPath = path_1.default.join(userScriptsDir, userScript);
165
- fs_1.default.unlinkSync(userScriptPath);
169
+ const userFilePath = path_1.default.join(userScriptsDir, userFile);
170
+ fs_1.default.unlinkSync(userFilePath);
166
171
  cleanedCount++;
167
- console.log(chalk_1.default.yellow(` - ${userScript} (removed from registry)`));
172
+ console.log(chalk_1.default.yellow(` - ${userFile} (removed from registry)`));
173
+ // Cleanup empty directories
174
+ try {
175
+ const dir = path_1.default.dirname(userFilePath);
176
+ if (fs_1.default.existsSync(dir) && fs_1.default.readdirSync(dir).length === 0) {
177
+ fs_1.default.rmdirSync(dir);
178
+ }
179
+ }
180
+ catch (e) { }
168
181
  }
169
182
  catch (error) {
170
- console.warn(chalk_1.default.yellow(`⚠️ Could not remove obsolete script ${userScript}: ${error}`));
183
+ console.warn(chalk_1.default.yellow(`⚠️ Could not remove obsolete script ${userFile}: ${error}`));
171
184
  }
172
185
  }
173
186
  }
@@ -185,21 +198,6 @@ function getUserScriptPath(scriptName) {
185
198
  function userScriptExists(scriptName) {
186
199
  return fs_1.default.existsSync(getUserScriptPath(scriptName));
187
200
  }
188
- /**
189
- * Get all dependent script files from the registry (those with FRAIM source dependencies)
190
- */
191
- function getDependentRegistryScripts(registryPath) {
192
- const scriptsPath = path_1.default.join(registryPath, 'scripts');
193
- if (!fs_1.default.existsSync(scriptsPath)) {
194
- return [];
195
- }
196
- const entries = fs_1.default.readdirSync(scriptsPath, { withFileTypes: true });
197
- const allScripts = entries
198
- .filter(entry => entry.isFile() && (entry.name.endsWith('.sh') || entry.name.endsWith('.ts') || entry.name.endsWith('.js')))
199
- .map(entry => path_1.default.join(scriptsPath, entry.name));
200
- // Only return scripts that have dependencies
201
- return allScripts.filter(scriptPath => !isScriptSelfContained(scriptPath));
202
- }
203
201
  /**
204
202
  * Validate that all expected scripts are present in user directory
205
203
  */
@@ -187,52 +187,31 @@ async function testScriptCategorizationAccuracy() {
187
187
  try {
188
188
  const registryPath = path_1.default.resolve(__dirname, '../registry');
189
189
  if (!fs_1.default.existsSync(registryPath)) {
190
- console.log(' ⚠️ Registry not found, skipping categorization accuracy test');
190
+ console.log(' ⚠️ Registry not found, skipping script sync test');
191
191
  return true;
192
192
  }
193
- const { getRegistryScripts, getDependentRegistryScripts, isScriptSelfContained } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
194
- const selfContainedScripts = getRegistryScripts(registryPath);
195
- const dependentScripts = getDependentRegistryScripts(registryPath);
196
- console.log(` 📊 Categorization results:`);
197
- console.log(` Self-contained: ${selfContainedScripts.length} scripts`);
198
- console.log(` Dependent: ${dependentScripts.length} scripts`);
199
- // Verify specific known categorizations
200
- const knownSelfContained = [
193
+ const { getRegistryScripts } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
194
+ const allScripts = getRegistryScripts(registryPath);
195
+ console.log(` 📊 Script sync results:`);
196
+ console.log(` Total scripts: ${allScripts.length} scripts`);
197
+ // Verify some known scripts exist
198
+ const knownScripts = [
201
199
  'prep-issue.sh',
202
200
  'code-quality-check.sh',
203
201
  'exec-with-timeout.ts',
204
- 'evaluate-code-quality.ts'
205
- ];
206
- const knownDependent = [
207
- 'fraim-config.ts',
208
- 'build-scripts-generator.ts'
202
+ 'evaluate-code-quality.ts',
203
+ 'comprehensive-explorer.py',
204
+ 'interactive-explorer.py',
205
+ 'scrape-site.py'
209
206
  ];
210
- const selfContainedNames = selfContainedScripts.map(p => path_1.default.basename(p));
211
- const dependentNames = dependentScripts.map(p => path_1.default.basename(p));
212
- for (const scriptName of knownSelfContained) {
213
- const scriptPath = path_1.default.join(registryPath, 'scripts', scriptName);
214
- if (fs_1.default.existsSync(scriptPath)) {
215
- node_assert_1.default.ok(selfContainedNames.includes(scriptName), `${scriptName} should be categorized as self-contained`);
216
- node_assert_1.default.ok(isScriptSelfContained(scriptPath), `${scriptName} should be detected as self-contained`);
217
- }
218
- }
219
- for (const scriptName of knownDependent) {
207
+ const scriptNames = allScripts.map(p => path_1.default.basename(p));
208
+ for (const scriptName of knownScripts) {
220
209
  const scriptPath = path_1.default.join(registryPath, 'scripts', scriptName);
221
210
  if (fs_1.default.existsSync(scriptPath)) {
222
- node_assert_1.default.ok(dependentNames.includes(scriptName), `${scriptName} should be categorized as dependent`);
223
- node_assert_1.default.ok(!isScriptSelfContained(scriptPath), `${scriptName} should be detected as dependent`);
211
+ node_assert_1.default.ok(scriptNames.includes(scriptName), `${scriptName} should be included in sync`);
224
212
  }
225
213
  }
226
- // Verify no script is in both categories
227
- const intersection = selfContainedNames.filter(name => dependentNames.includes(name));
228
- node_assert_1.default.strictEqual(intersection.length, 0, 'No script should be in both categories');
229
- // Verify all scripts are categorized
230
- const allScripts = fs_1.default.readdirSync(path_1.default.join(registryPath, 'scripts'))
231
- .filter(file => file.endsWith('.sh') || file.endsWith('.ts') || file.endsWith('.js'));
232
- const categorizedScripts = [...selfContainedNames, ...dependentNames];
233
- const uncategorized = allScripts.filter(script => !categorizedScripts.includes(script));
234
- node_assert_1.default.strictEqual(uncategorized.length, 0, `All scripts should be categorized. Uncategorized: ${uncategorized.join(', ')}`);
235
- console.log(' ✅ Script categorization accuracy verified!');
214
+ console.log(' ✅ All known scripts are included');
236
215
  return true;
237
216
  }
238
217
  catch (error) {
@@ -77,24 +77,15 @@ const helper = require('../../src/utils/helper');
77
77
  console.log('This script also depends on FRAIM source code');
78
78
  `;
79
79
  fs_1.default.writeFileSync(path_1.default.join(scriptsDir, 'dependent.js'), dependentJS);
80
- // Test the detection logic
81
- const { isScriptSelfContained, getRegistryScripts, getDependentRegistryScripts } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
82
- // Test individual script detection
83
- node_assert_1.default.ok(isScriptSelfContained(path_1.default.join(scriptsDir, 'self-contained.sh')), 'Shell script should be self-contained');
84
- node_assert_1.default.ok(isScriptSelfContained(path_1.default.join(scriptsDir, 'self-contained.ts')), 'Self-contained TS should be detected');
85
- node_assert_1.default.ok(!isScriptSelfContained(path_1.default.join(scriptsDir, 'dependent.ts')), 'Dependent TS should not be self-contained');
86
- node_assert_1.default.ok(!isScriptSelfContained(path_1.default.join(scriptsDir, 'dependent.js')), 'Dependent JS should not be self-contained');
87
- // Test batch detection
88
- const selfContainedScripts = getRegistryScripts(tempDir);
89
- const dependentScripts = getDependentRegistryScripts(tempDir);
90
- node_assert_1.default.strictEqual(selfContainedScripts.length, 2, 'Should find 2 self-contained scripts');
91
- node_assert_1.default.strictEqual(dependentScripts.length, 2, 'Should find 2 dependent scripts');
92
- // Verify correct categorization
93
- const selfContainedNames = selfContainedScripts.map(p => path_1.default.basename(p)).sort();
94
- const dependentNames = dependentScripts.map(p => path_1.default.basename(p)).sort();
95
- node_assert_1.default.deepStrictEqual(selfContainedNames, ['self-contained.sh', 'self-contained.ts'], 'Self-contained scripts correctly identified');
96
- node_assert_1.default.deepStrictEqual(dependentNames, ['dependent.js', 'dependent.ts'], 'Dependent scripts correctly identified');
97
- console.log(' ✅ Self-contained script detection verified!');
80
+ // Test the sync logic - all scripts should be synced now
81
+ const { getRegistryScripts } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
82
+ // Test batch detection - should get all scripts
83
+ const allScripts = getRegistryScripts(tempDir);
84
+ node_assert_1.default.strictEqual(allScripts.length, 4, 'Should find all 4 scripts');
85
+ // Verify all scripts are included
86
+ const scriptNames = allScripts.map(p => path_1.default.basename(p)).sort();
87
+ node_assert_1.default.deepStrictEqual(scriptNames, ['dependent.js', 'dependent.ts', 'self-contained.sh', 'self-contained.ts'], 'All scripts should be included');
88
+ console.log(' ✅ Script sync detection verified!');
98
89
  return true;
99
90
  }
100
91
  catch (error) {
@@ -142,13 +133,13 @@ console.log('Dependent TypeScript script');
142
133
  // Override user directory for testing
143
134
  process.env.FRAIM_USER_DIR = userFraimDir;
144
135
  const syncResult = syncScriptsToUserDirectory(registryDir);
145
- // Verify sync results
146
- node_assert_1.default.strictEqual(syncResult.synced, 2, 'Should sync 2 self-contained scripts');
147
- node_assert_1.default.strictEqual(syncResult.ephemeral, 1, 'Should identify 1 dependent script for ephemeral execution');
148
- // Verify only self-contained scripts were copied
136
+ // Verify sync results - now all scripts are synced
137
+ node_assert_1.default.strictEqual(syncResult.synced, 3, 'Should sync all 3 scripts');
138
+ node_assert_1.default.strictEqual(syncResult.ephemeral, 0, 'No ephemeral scripts (all are synced)');
139
+ // Verify all scripts were copied
149
140
  node_assert_1.default.ok(fs_1.default.existsSync(path_1.default.join(userScriptsDir, 'shell-script.sh')), 'Shell script should be synced');
150
141
  node_assert_1.default.ok(fs_1.default.existsSync(path_1.default.join(userScriptsDir, 'self-contained.ts')), 'Self-contained TS should be synced');
151
- node_assert_1.default.ok(!fs_1.default.existsSync(path_1.default.join(userScriptsDir, 'dependent.ts')), 'Dependent TS should NOT be synced');
142
+ node_assert_1.default.ok(fs_1.default.existsSync(path_1.default.join(userScriptsDir, 'dependent.ts')), 'Dependent TS should also be synced');
152
143
  // Verify executable permissions on Unix
153
144
  if (process.platform !== 'win32') {
154
145
  const shellScriptPath = path_1.default.join(userScriptsDir, 'shell-script.sh');
@@ -181,52 +172,32 @@ async function testActualRegistryScriptCategorization() {
181
172
  console.log(' ⚠️ Registry not found, skipping actual script categorization test');
182
173
  return true;
183
174
  }
184
- const { getRegistryScripts, getDependentRegistryScripts } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
185
- const selfContainedScripts = getRegistryScripts(registryPath);
186
- const dependentScripts = getDependentRegistryScripts(registryPath);
187
- console.log(` 📊 Found ${selfContainedScripts.length} self-contained scripts:`);
188
- for (const script of selfContainedScripts) {
175
+ const { getRegistryScripts } = await Promise.resolve().then(() => __importStar(require('../src/utils/script-sync-utils')));
176
+ const allScripts = getRegistryScripts(registryPath);
177
+ console.log(` 📊 Found ${allScripts.length} scripts to sync:`);
178
+ for (const script of allScripts) {
189
179
  console.log(` ✅ ${path_1.default.basename(script)}`);
190
180
  }
191
- console.log(` 📊 Found ${dependentScripts.length} dependent scripts:`);
192
- for (const script of dependentScripts) {
193
- console.log(` 🔗 ${path_1.default.basename(script)}`);
194
- }
195
- // Verify expected scripts are categorized correctly
196
- const selfContainedNames = selfContainedScripts.map(p => path_1.default.basename(p));
197
- const dependentNames = dependentScripts.map(p => path_1.default.basename(p));
198
- // prep-issue.sh should be self-contained (it's a shell script)
199
- node_assert_1.default.ok(selfContainedNames.includes('prep-issue.sh'), 'prep-issue.sh should be self-contained');
200
- // Scripts with FRAIM imports should be dependent
201
- const expectedDependentScripts = [
202
- 'fraim-config.ts',
203
- 'build-scripts-generator.ts'
204
- ];
205
- for (const expectedDependent of expectedDependentScripts) {
206
- if (fs_1.default.existsSync(path_1.default.join(registryPath, 'scripts', expectedDependent))) {
207
- node_assert_1.default.ok(dependentNames.includes(expectedDependent), `${expectedDependent} should be dependent`);
208
- }
209
- }
210
- // Scripts that should be self-contained
211
- const expectedSelfContainedScripts = [
212
- 'prep-issue.sh',
213
- 'evaluate-code-quality.ts', // This only uses __dirname and standard modules
214
- 'code-quality-check.sh'
181
+ // Verify expected scripts are included
182
+ const scriptNames = allScripts.map(p => path_1.default.basename(p));
183
+ // prep-issue.sh should be included
184
+ node_assert_1.default.ok(scriptNames.includes('prep-issue.sh'), 'prep-issue.sh should be included');
185
+ // Python scripts should be included
186
+ const expectedPythonScripts = [
187
+ 'comprehensive-explorer.py',
188
+ 'interactive-explorer.py',
189
+ 'scrape-site.py'
215
190
  ];
216
- for (const expectedSelfContained of expectedSelfContainedScripts) {
217
- if (fs_1.default.existsSync(path_1.default.join(registryPath, 'scripts', expectedSelfContained))) {
218
- node_assert_1.default.ok(selfContainedNames.includes(expectedSelfContained), `${expectedSelfContained} should be self-contained`);
191
+ for (const expectedScript of expectedPythonScripts) {
192
+ if (fs_1.default.existsSync(path_1.default.join(registryPath, 'scripts', expectedScript))) {
193
+ node_assert_1.default.ok(scriptNames.includes(expectedScript), `${expectedScript} should be included`);
219
194
  }
220
195
  }
221
- // Verify we have a reasonable split
222
- const totalScripts = selfContainedScripts.length + dependentScripts.length;
223
- node_assert_1.default.ok(totalScripts > 0, 'Should find some scripts in registry');
224
- node_assert_1.default.ok(selfContainedScripts.length > 0, 'Should have some self-contained scripts');
225
- console.log(' ✅ Actual registry script categorization verified!');
196
+ console.log(' ✅ Actual registry script sync verified!');
226
197
  return true;
227
198
  }
228
199
  catch (error) {
229
- console.error(' ❌ Registry script categorization test failed:', error);
200
+ console.error(' ❌ Registry script sync test failed:', error);
230
201
  return false;
231
202
  }
232
203
  }