@sylphx/flow 1.4.11 ā 1.4.13
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/CHANGELOG.md +20 -0
- package/package.json +1 -1
- package/src/commands/flow-command.ts +4 -0
- package/src/commands/flow-orchestrator.ts +53 -0
- package/src/utils/sync-utils.ts +45 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @sylphx/flow
|
|
2
2
|
|
|
3
|
+
## 1.4.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1d0ac4e: Add startup check for new templates:
|
|
8
|
+
- Detects missing templates on startup (new templates not installed locally)
|
|
9
|
+
- Shows notification with count of new agents/commands/rules
|
|
10
|
+
- Prompts user to run --sync to install
|
|
11
|
+
- Ignores unknown files (custom user files)
|
|
12
|
+
- Non-blocking - just informational
|
|
13
|
+
|
|
14
|
+
## 1.4.12
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- d88d280: Show missing templates in sync preview:
|
|
19
|
+
- Added "Will install (new templates)" section
|
|
20
|
+
- Users can now see which templates will be newly installed
|
|
21
|
+
- Better visibility into what changes sync will make
|
|
22
|
+
|
|
3
23
|
## 1.4.11
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -621,6 +621,7 @@ async function executeFlowOnce(prompt: string | undefined, options: FlowOptions)
|
|
|
621
621
|
const {
|
|
622
622
|
checkUpgrades,
|
|
623
623
|
checkComponentIntegrity,
|
|
624
|
+
checkSyncStatus,
|
|
624
625
|
selectTarget,
|
|
625
626
|
initializeProject,
|
|
626
627
|
launchTarget,
|
|
@@ -675,6 +676,9 @@ async function executeFlowOnce(prompt: string | undefined, options: FlowOptions)
|
|
|
675
676
|
|
|
676
677
|
// Step 2.5: Check component integrity (only if we have valid state)
|
|
677
678
|
await checkComponentIntegrity(state, options);
|
|
679
|
+
|
|
680
|
+
// Step 2.6: Check sync status (new templates available)
|
|
681
|
+
await checkSyncStatus(state, options);
|
|
678
682
|
}
|
|
679
683
|
|
|
680
684
|
// Step 3: Initialize (only if actually needed)
|
|
@@ -147,6 +147,59 @@ export async function checkComponentIntegrity(
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Step 2.5: Check sync status (new templates available)
|
|
152
|
+
* Only checks for missing templates, ignores unknown files
|
|
153
|
+
*/
|
|
154
|
+
export async function checkSyncStatus(
|
|
155
|
+
state: ProjectState,
|
|
156
|
+
options: FlowOptions
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
// Skip if not initialized, syncing, or init-only
|
|
159
|
+
if (!state.initialized || options.sync || options.initOnly) return;
|
|
160
|
+
|
|
161
|
+
// Skip in quick mode
|
|
162
|
+
if (options.quick) return;
|
|
163
|
+
|
|
164
|
+
// Need target to check sync status
|
|
165
|
+
if (!state.target) return;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const { buildSyncManifest } = await import('../utils/sync-utils.js');
|
|
169
|
+
const target = targetManager.getTarget(state.target);
|
|
170
|
+
|
|
171
|
+
if (target._tag === 'None') return;
|
|
172
|
+
|
|
173
|
+
const manifest = await buildSyncManifest(process.cwd(), target.value);
|
|
174
|
+
|
|
175
|
+
// Count missing templates (new templates not installed locally)
|
|
176
|
+
const missingCount =
|
|
177
|
+
manifest.agents.missing.length +
|
|
178
|
+
manifest.slashCommands.missing.length +
|
|
179
|
+
manifest.rules.missing.length;
|
|
180
|
+
|
|
181
|
+
// Only prompt if there are missing templates
|
|
182
|
+
if (missingCount > 0) {
|
|
183
|
+
const missing: string[] = [];
|
|
184
|
+
|
|
185
|
+
if (manifest.agents.missing.length > 0) {
|
|
186
|
+
missing.push(`${manifest.agents.missing.length} agent${manifest.agents.missing.length > 1 ? 's' : ''}`);
|
|
187
|
+
}
|
|
188
|
+
if (manifest.slashCommands.missing.length > 0) {
|
|
189
|
+
missing.push(`${manifest.slashCommands.missing.length} command${manifest.slashCommands.missing.length > 1 ? 's' : ''}`);
|
|
190
|
+
}
|
|
191
|
+
if (manifest.rules.missing.length > 0) {
|
|
192
|
+
missing.push(`${manifest.rules.missing.length} rule${manifest.rules.missing.length > 1 ? 's' : ''}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log(chalk.yellow(`\nš¦ New templates available: ${missing.join(', ')}\n`));
|
|
196
|
+
console.log(chalk.dim(` Run ${chalk.cyan('sylphx-flow --sync')} to install new templates\n`));
|
|
197
|
+
}
|
|
198
|
+
} catch (error) {
|
|
199
|
+
// Silently ignore sync check errors - don't block execution
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
150
203
|
/**
|
|
151
204
|
* Step 3: Handle target selection
|
|
152
205
|
* Returns the selected target ID
|
package/src/utils/sync-utils.ts
CHANGED
|
@@ -31,8 +31,9 @@ const FLOW_RULES = scanTemplateDir(getRulesDir());
|
|
|
31
31
|
* Categorized files for sync
|
|
32
32
|
*/
|
|
33
33
|
interface CategorizedFiles {
|
|
34
|
-
inFlow: string[]; // Files that exist in Flow templates
|
|
34
|
+
inFlow: string[]; // Files that exist locally and in Flow templates (will reinstall)
|
|
35
35
|
unknown: string[]; // Files not in Flow templates (custom or removed)
|
|
36
|
+
missing: string[]; // Flow templates that don't exist locally (will install)
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/**
|
|
@@ -50,11 +51,15 @@ interface SyncManifest {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
|
-
* Categorize files into Flow templates vs unknown
|
|
54
|
+
* Categorize files into Flow templates vs unknown, and detect missing templates
|
|
54
55
|
*/
|
|
55
56
|
function categorizeFiles(files: string[], flowTemplates: string[]): CategorizedFiles {
|
|
56
57
|
const inFlow: string[] = [];
|
|
57
58
|
const unknown: string[] = [];
|
|
59
|
+
const existingBasenames = files.map((f) => path.basename(f));
|
|
60
|
+
|
|
61
|
+
// Find missing Flow templates (in flowTemplates but not in files)
|
|
62
|
+
const missing = flowTemplates.filter((template) => !existingBasenames.includes(template));
|
|
58
63
|
|
|
59
64
|
for (const file of files) {
|
|
60
65
|
const basename = path.basename(file);
|
|
@@ -65,7 +70,7 @@ function categorizeFiles(files: string[], flowTemplates: string[]): CategorizedF
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
return { inFlow, unknown };
|
|
73
|
+
return { inFlow, unknown, missing };
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
/**
|
|
@@ -73,9 +78,9 @@ function categorizeFiles(files: string[], flowTemplates: string[]): CategorizedF
|
|
|
73
78
|
*/
|
|
74
79
|
export async function buildSyncManifest(cwd: string, target: Target): Promise<SyncManifest> {
|
|
75
80
|
const manifest: SyncManifest = {
|
|
76
|
-
agents: { inFlow: [], unknown: [] },
|
|
77
|
-
slashCommands: { inFlow: [], unknown: [] },
|
|
78
|
-
rules: { inFlow: [], unknown: [] },
|
|
81
|
+
agents: { inFlow: [], unknown: [], missing: [] },
|
|
82
|
+
slashCommands: { inFlow: [], unknown: [], missing: [] },
|
|
83
|
+
rules: { inFlow: [], unknown: [], missing: [] },
|
|
79
84
|
mcpServers: { inRegistry: [], notInRegistry: [] },
|
|
80
85
|
preserve: [],
|
|
81
86
|
};
|
|
@@ -214,6 +219,40 @@ export function showSyncPreview(manifest: SyncManifest, cwd: string): void {
|
|
|
214
219
|
}
|
|
215
220
|
}
|
|
216
221
|
|
|
222
|
+
// Missing templates section (will be installed)
|
|
223
|
+
const hasMissingFiles =
|
|
224
|
+
manifest.agents.missing.length > 0 ||
|
|
225
|
+
manifest.slashCommands.missing.length > 0 ||
|
|
226
|
+
manifest.rules.missing.length > 0;
|
|
227
|
+
|
|
228
|
+
if (hasMissingFiles) {
|
|
229
|
+
console.log(chalk.green('Will install (new templates):\n'));
|
|
230
|
+
|
|
231
|
+
if (manifest.agents.missing.length > 0) {
|
|
232
|
+
console.log(chalk.dim(' Agents:'));
|
|
233
|
+
manifest.agents.missing.forEach((file) => {
|
|
234
|
+
console.log(chalk.dim(` + ${file}`));
|
|
235
|
+
});
|
|
236
|
+
console.log('');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (manifest.slashCommands.missing.length > 0) {
|
|
240
|
+
console.log(chalk.dim(' Commands:'));
|
|
241
|
+
manifest.slashCommands.missing.forEach((file) => {
|
|
242
|
+
console.log(chalk.dim(` + ${file}`));
|
|
243
|
+
});
|
|
244
|
+
console.log('');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (manifest.rules.missing.length > 0) {
|
|
248
|
+
console.log(chalk.dim(' Rules:'));
|
|
249
|
+
manifest.rules.missing.forEach((file) => {
|
|
250
|
+
console.log(chalk.dim(` + ${file}`));
|
|
251
|
+
});
|
|
252
|
+
console.log('');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
217
256
|
// Unknown files section
|
|
218
257
|
const hasUnknownFiles =
|
|
219
258
|
manifest.agents.unknown.length > 0 ||
|