@synergenius/flow-weaver 0.22.8 → 0.22.10
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/dist/agent/index.d.ts +5 -1
- package/dist/agent/index.js +3 -1
- package/dist/agent/providers/openai-compat.d.ts +25 -0
- package/dist/agent/providers/openai-compat.js +204 -0
- package/dist/agent/providers/platform.d.ts +23 -0
- package/dist/agent/providers/platform.js +130 -0
- package/dist/cli/commands/auth.d.ts +8 -0
- package/dist/cli/commands/auth.js +137 -0
- package/dist/cli/commands/deploy.d.ts +6 -0
- package/dist/cli/commands/deploy.js +97 -0
- package/dist/cli/commands/init.d.ts +2 -1
- package/dist/cli/commands/init.js +28 -2
- package/dist/cli/config/credentials.d.ts +15 -0
- package/dist/cli/config/credentials.js +43 -0
- package/dist/cli/config/platform-client.d.ts +36 -0
- package/dist/cli/config/platform-client.js +122 -0
- package/dist/cli/flow-weaver.mjs +806 -343
- package/dist/cli/index.js +66 -0
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/package.json +1 -1
|
@@ -32,6 +32,7 @@ export interface InitConfig {
|
|
|
32
32
|
/** Free-text description when user picked "Something else" */
|
|
33
33
|
useCaseDescription?: string;
|
|
34
34
|
mcp: boolean;
|
|
35
|
+
installWeaver: boolean;
|
|
35
36
|
}
|
|
36
37
|
export interface InitReport {
|
|
37
38
|
projectDir: string;
|
|
@@ -55,7 +56,7 @@ export declare function validateProjectName(name: string): string | true;
|
|
|
55
56
|
export declare function toWorkflowName(projectName: string): string;
|
|
56
57
|
export declare function isNonInteractive(): boolean;
|
|
57
58
|
export declare function resolveInitConfig(dirArg: string | undefined, options: InitOptions): Promise<InitConfig>;
|
|
58
|
-
export declare function generateProjectFiles(projectName: string, template: string, format?: TModuleFormat, persona?: PersonaId): Record<string, string>;
|
|
59
|
+
export declare function generateProjectFiles(projectName: string, template: string, format?: TModuleFormat, persona?: PersonaId, installWeaver?: boolean): Record<string, string>;
|
|
59
60
|
export declare function scaffoldProject(targetDir: string, files: Record<string, string>, options: {
|
|
60
61
|
force: boolean;
|
|
61
62
|
}): {
|
|
@@ -183,6 +183,17 @@ export async function resolveInitConfig(dirArg, options) {
|
|
|
183
183
|
if (!useCaseDescription)
|
|
184
184
|
useCaseDescription = undefined;
|
|
185
185
|
}
|
|
186
|
+
// 3c. Weaver AI assistant opt-in
|
|
187
|
+
let installWeaver;
|
|
188
|
+
if (skipPrompts) {
|
|
189
|
+
installWeaver = false;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
installWeaver = await confirm({
|
|
193
|
+
message: 'Install Weaver AI assistant? (Recommended)\n Weaver helps you create, modify, and manage workflows with AI.',
|
|
194
|
+
default: true,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
186
197
|
// 4. MCP setup (nocode, vibecoder, lowcode: prompt; expert: skip unless --mcp)
|
|
187
198
|
let mcp;
|
|
188
199
|
if (options.mcp !== undefined) {
|
|
@@ -255,10 +266,11 @@ export async function resolveInitConfig(dirArg, options) {
|
|
|
255
266
|
useCase,
|
|
256
267
|
useCaseDescription,
|
|
257
268
|
mcp,
|
|
269
|
+
installWeaver,
|
|
258
270
|
};
|
|
259
271
|
}
|
|
260
272
|
// ── Pure file generation ─────────────────────────────────────────────────────
|
|
261
|
-
export function generateProjectFiles(projectName, template, format = 'esm', persona = 'expert') {
|
|
273
|
+
export function generateProjectFiles(projectName, template, format = 'esm', persona = 'expert', installWeaver = false) {
|
|
262
274
|
const workflowName = toWorkflowName(projectName);
|
|
263
275
|
const workflowFile = `${projectName}-workflow.ts`;
|
|
264
276
|
const tmpl = getWorkflowTemplate(template);
|
|
@@ -284,6 +296,7 @@ export function generateProjectFiles(projectName, template, format = 'esm', pers
|
|
|
284
296
|
scripts,
|
|
285
297
|
dependencies: {
|
|
286
298
|
'@synergenius/flow-weaver': 'latest',
|
|
299
|
+
...(installWeaver ? { '@synergenius/flow-weaver-pack-weaver': 'latest' } : {}),
|
|
287
300
|
},
|
|
288
301
|
devDependencies: {
|
|
289
302
|
typescript: '^5.3.0',
|
|
@@ -382,6 +395,10 @@ export function generateProjectFiles(projectName, template, format = 'esm', pers
|
|
|
382
395
|
if (persona === 'lowcode') {
|
|
383
396
|
files['examples/example-workflow.ts'] = generateExampleWorkflow(projectName);
|
|
384
397
|
}
|
|
398
|
+
// Add Weaver config if opted in
|
|
399
|
+
if (installWeaver) {
|
|
400
|
+
files['.weaver.json'] = JSON.stringify({ provider: 'auto', approval: 'auto' }, null, 2) + '\n';
|
|
401
|
+
}
|
|
385
402
|
return files;
|
|
386
403
|
}
|
|
387
404
|
// ── Filesystem writer ────────────────────────────────────────────────────────
|
|
@@ -502,7 +519,7 @@ export async function initCommand(dirArg, options) {
|
|
|
502
519
|
throw new Error(`${config.targetDir} already contains a package.json. Use --force to overwrite.`);
|
|
503
520
|
}
|
|
504
521
|
// Generate and scaffold
|
|
505
|
-
const files = generateProjectFiles(config.projectName, config.template, config.format, config.persona);
|
|
522
|
+
const files = generateProjectFiles(config.projectName, config.template, config.format, config.persona, config.installWeaver);
|
|
506
523
|
const { filesCreated, filesSkipped } = scaffoldProject(config.targetDir, files, {
|
|
507
524
|
force: config.force,
|
|
508
525
|
});
|
|
@@ -622,6 +639,15 @@ export async function initCommand(dirArg, options) {
|
|
|
622
639
|
logger.warn(`Compile failed: ${compileResult.error}`);
|
|
623
640
|
}
|
|
624
641
|
}
|
|
642
|
+
if (config.installWeaver) {
|
|
643
|
+
logger.success('Weaver AI assistant installed');
|
|
644
|
+
logger.newline();
|
|
645
|
+
logger.log(' Weaver installed. Try:');
|
|
646
|
+
logger.log(' flow-weaver weaver assistant # AI assistant');
|
|
647
|
+
logger.log(' flow-weaver weaver bot "..." # create workflows with AI');
|
|
648
|
+
logger.log(' flow-weaver weaver examples # see what\'s possible');
|
|
649
|
+
logger.newline();
|
|
650
|
+
}
|
|
625
651
|
// Read the workflow code for preview
|
|
626
652
|
const workflowCode = files[`src/${workflowFile}`] ?? null;
|
|
627
653
|
// Persona-specific rich output
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface StoredCredentials {
|
|
2
|
+
token: string;
|
|
3
|
+
email: string;
|
|
4
|
+
plan: 'free' | 'pro' | 'business';
|
|
5
|
+
platformUrl: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
userId?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadCredentials(): StoredCredentials | null;
|
|
10
|
+
export declare function saveCredentials(creds: StoredCredentials): void;
|
|
11
|
+
export declare function clearCredentials(): void;
|
|
12
|
+
export declare function isTokenExpired(creds: StoredCredentials): boolean;
|
|
13
|
+
export declare function getPlatformUrl(): string;
|
|
14
|
+
export declare function isLoggedIn(): boolean;
|
|
15
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
const FW_CONFIG_DIR = path.join(os.homedir(), '.fw');
|
|
5
|
+
const CREDENTIALS_FILE = path.join(FW_CONFIG_DIR, 'credentials.json');
|
|
6
|
+
export function loadCredentials() {
|
|
7
|
+
if (!fs.existsSync(CREDENTIALS_FILE))
|
|
8
|
+
return null;
|
|
9
|
+
try {
|
|
10
|
+
const data = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, 'utf-8'));
|
|
11
|
+
if (isTokenExpired(data))
|
|
12
|
+
return null;
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function saveCredentials(creds) {
|
|
20
|
+
fs.mkdirSync(FW_CONFIG_DIR, { recursive: true });
|
|
21
|
+
fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), 'utf-8');
|
|
22
|
+
try {
|
|
23
|
+
fs.chmodSync(CREDENTIALS_FILE, 0o600);
|
|
24
|
+
}
|
|
25
|
+
catch { /* Windows */ }
|
|
26
|
+
}
|
|
27
|
+
export function clearCredentials() {
|
|
28
|
+
try {
|
|
29
|
+
fs.unlinkSync(CREDENTIALS_FILE);
|
|
30
|
+
}
|
|
31
|
+
catch { /* not found */ }
|
|
32
|
+
}
|
|
33
|
+
export function isTokenExpired(creds) {
|
|
34
|
+
return Date.now() > creds.expiresAt;
|
|
35
|
+
}
|
|
36
|
+
export function getPlatformUrl() {
|
|
37
|
+
const creds = loadCredentials();
|
|
38
|
+
return creds?.platformUrl ?? process.env.FW_PLATFORM_URL ?? 'https://app.synergenius.pt';
|
|
39
|
+
}
|
|
40
|
+
export function isLoggedIn() {
|
|
41
|
+
return loadCredentials() !== null;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { StoredCredentials } from './credentials.js';
|
|
2
|
+
export declare class PlatformClient {
|
|
3
|
+
private baseUrl;
|
|
4
|
+
private token;
|
|
5
|
+
constructor(creds: StoredCredentials);
|
|
6
|
+
private fetch;
|
|
7
|
+
getUser(): Promise<{
|
|
8
|
+
id: string;
|
|
9
|
+
email: string;
|
|
10
|
+
name: string;
|
|
11
|
+
plan: string;
|
|
12
|
+
}>;
|
|
13
|
+
pushWorkflow(name: string, source: string): Promise<{
|
|
14
|
+
slug: string;
|
|
15
|
+
version: number;
|
|
16
|
+
}>;
|
|
17
|
+
deploy(slug: string): Promise<{
|
|
18
|
+
slug: string;
|
|
19
|
+
status: string;
|
|
20
|
+
}>;
|
|
21
|
+
undeploy(slug: string): Promise<void>;
|
|
22
|
+
listDeployments(): Promise<Array<{
|
|
23
|
+
slug: string;
|
|
24
|
+
status: string;
|
|
25
|
+
workflowName?: string;
|
|
26
|
+
}>>;
|
|
27
|
+
getUsage(): Promise<{
|
|
28
|
+
executions: number;
|
|
29
|
+
aiCalls: number;
|
|
30
|
+
plan: string;
|
|
31
|
+
}>;
|
|
32
|
+
streamChat(message: string, conversationId?: string): AsyncGenerator<Record<string, unknown>>;
|
|
33
|
+
validate(): Promise<boolean>;
|
|
34
|
+
}
|
|
35
|
+
export declare function createPlatformClient(creds: StoredCredentials): PlatformClient;
|
|
36
|
+
//# sourceMappingURL=platform-client.d.ts.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export class PlatformClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
token;
|
|
4
|
+
constructor(creds) {
|
|
5
|
+
this.baseUrl = creds.platformUrl.replace(/\/+$/, '');
|
|
6
|
+
this.token = creds.token;
|
|
7
|
+
}
|
|
8
|
+
async fetch(path, opts = {}) {
|
|
9
|
+
const isApiKey = this.token.startsWith('fw_');
|
|
10
|
+
const headers = {
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
...(isApiKey
|
|
13
|
+
? { 'X-API-Key': this.token }
|
|
14
|
+
: { Authorization: `Bearer ${this.token}` }),
|
|
15
|
+
...(opts.headers ?? {}),
|
|
16
|
+
};
|
|
17
|
+
return fetch(`${this.baseUrl}${path}`, { ...opts, headers });
|
|
18
|
+
}
|
|
19
|
+
// Auth
|
|
20
|
+
async getUser() {
|
|
21
|
+
const resp = await this.fetch('/auth/me');
|
|
22
|
+
if (!resp.ok)
|
|
23
|
+
throw new Error(`Auth failed: ${resp.status}`);
|
|
24
|
+
const data = await resp.json();
|
|
25
|
+
return data.user;
|
|
26
|
+
}
|
|
27
|
+
// Workflows
|
|
28
|
+
async pushWorkflow(name, source) {
|
|
29
|
+
// Try update first, then create
|
|
30
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
|
|
31
|
+
let resp = await this.fetch(`/workflows/${slug}`, {
|
|
32
|
+
method: 'PUT',
|
|
33
|
+
body: JSON.stringify({ source, name }),
|
|
34
|
+
});
|
|
35
|
+
if (resp.status === 404) {
|
|
36
|
+
resp = await this.fetch('/workflows', {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
body: JSON.stringify({ source, name }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (!resp.ok) {
|
|
42
|
+
const err = await resp.json().catch(() => ({ error: resp.statusText }));
|
|
43
|
+
throw new Error(err.error ?? `Push failed: ${resp.status}`);
|
|
44
|
+
}
|
|
45
|
+
const data = await resp.json();
|
|
46
|
+
return data.workflow;
|
|
47
|
+
}
|
|
48
|
+
async deploy(slug) {
|
|
49
|
+
const resp = await this.fetch(`/workflows/${slug}/deploy`, { method: 'POST' });
|
|
50
|
+
if (!resp.ok) {
|
|
51
|
+
const err = await resp.json().catch(() => ({ error: resp.statusText }));
|
|
52
|
+
throw new Error(err.error ?? `Deploy failed: ${resp.status}`);
|
|
53
|
+
}
|
|
54
|
+
const data = await resp.json();
|
|
55
|
+
return data.deployment;
|
|
56
|
+
}
|
|
57
|
+
async undeploy(slug) {
|
|
58
|
+
const resp = await this.fetch(`/deployments/${slug}`, { method: 'DELETE' });
|
|
59
|
+
if (!resp.ok && resp.status !== 404)
|
|
60
|
+
throw new Error(`Undeploy failed: ${resp.status}`);
|
|
61
|
+
}
|
|
62
|
+
async listDeployments() {
|
|
63
|
+
const resp = await this.fetch('/deployments');
|
|
64
|
+
if (!resp.ok)
|
|
65
|
+
throw new Error(`List failed: ${resp.status}`);
|
|
66
|
+
const data = await resp.json();
|
|
67
|
+
return data.deployments;
|
|
68
|
+
}
|
|
69
|
+
// Usage
|
|
70
|
+
async getUsage() {
|
|
71
|
+
const resp = await this.fetch('/monitoring/usage');
|
|
72
|
+
if (!resp.ok)
|
|
73
|
+
return { executions: 0, aiCalls: 0, plan: 'unknown' };
|
|
74
|
+
return await resp.json();
|
|
75
|
+
}
|
|
76
|
+
// AI Chat streaming
|
|
77
|
+
async *streamChat(message, conversationId) {
|
|
78
|
+
const resp = await this.fetch('/ai-chat/stream', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
body: JSON.stringify({ message, conversationId }),
|
|
81
|
+
});
|
|
82
|
+
if (!resp.ok) {
|
|
83
|
+
const err = await resp.text();
|
|
84
|
+
throw new Error(`AI chat failed: ${resp.status} ${err.slice(0, 200)}`);
|
|
85
|
+
}
|
|
86
|
+
if (!resp.body)
|
|
87
|
+
return;
|
|
88
|
+
const reader = resp.body.getReader();
|
|
89
|
+
const decoder = new TextDecoder();
|
|
90
|
+
let buffer = '';
|
|
91
|
+
while (true) {
|
|
92
|
+
const { done, value } = await reader.read();
|
|
93
|
+
if (done)
|
|
94
|
+
break;
|
|
95
|
+
buffer += decoder.decode(value, { stream: true });
|
|
96
|
+
const lines = buffer.split('\n');
|
|
97
|
+
buffer = lines.pop() || '';
|
|
98
|
+
for (const line of lines) {
|
|
99
|
+
if (!line.startsWith('data: '))
|
|
100
|
+
continue;
|
|
101
|
+
try {
|
|
102
|
+
yield JSON.parse(line.slice(6));
|
|
103
|
+
}
|
|
104
|
+
catch { /* skip non-JSON */ }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Validate connection
|
|
109
|
+
async validate() {
|
|
110
|
+
try {
|
|
111
|
+
const resp = await this.fetch('/ready');
|
|
112
|
+
return resp.ok;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function createPlatformClient(creds) {
|
|
120
|
+
return new PlatformClient(creds);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=platform-client.js.map
|