@wayai/cli 0.1.0
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/commands/login.d.ts +4 -0
- package/dist/commands/login.js +123 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.js +14 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +4 -0
- package/dist/commands/pull.js +73 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +4 -0
- package/dist/commands/push.js +90 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +26 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +18 -0
- package/dist/lib/api-client.js +50 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth.d.ts +59 -0
- package/dist/lib/auth.js +191 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/config.js +37 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/diff-display.d.ts +8 -0
- package/dist/lib/diff-display.js +37 -0
- package/dist/lib/diff-display.js.map +1 -0
- package/dist/lib/parser.d.ts +11 -0
- package/dist/lib/parser.js +64 -0
- package/dist/lib/parser.js.map +1 -0
- package/dist/lib/types.d.ts +106 -0
- package/dist/lib/types.js +5 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +16 -0
- package/dist/lib/utils.js +38 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/yaml-writer.d.ts +13 -0
- package/dist/lib/yaml-writer.js +101 -0
- package/dist/lib/yaml-writer.js.map +1 -0
- package/package.json +41 -0
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication — OAuth PKCE flow + MCP token fallback
|
|
3
|
+
*/
|
|
4
|
+
import * as crypto from 'node:crypto';
|
|
5
|
+
import * as http from 'node:http';
|
|
6
|
+
import { readConfig } from './config.js';
|
|
7
|
+
/**
|
|
8
|
+
* Fetch auth configuration from the backend (Supabase URL, etc.)
|
|
9
|
+
*/
|
|
10
|
+
export async function fetchAuthConfig(apiUrl) {
|
|
11
|
+
const response = await fetch(`${apiUrl}/auth/config`);
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw new Error(`Failed to fetch auth config from ${apiUrl} (${response.status})`);
|
|
14
|
+
}
|
|
15
|
+
return response.json();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate PKCE code_verifier and code_challenge for OAuth
|
|
19
|
+
*/
|
|
20
|
+
export function generatePKCE() {
|
|
21
|
+
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
22
|
+
const codeChallenge = crypto
|
|
23
|
+
.createHash('sha256')
|
|
24
|
+
.update(codeVerifier)
|
|
25
|
+
.digest('base64url');
|
|
26
|
+
return { codeVerifier, codeChallenge };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Start a local HTTP server that waits for the OAuth callback.
|
|
30
|
+
* Returns the authorization code received.
|
|
31
|
+
*/
|
|
32
|
+
export function startCallbackServer(port, timeoutMs = 120_000) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const server = http.createServer((req, res) => {
|
|
35
|
+
const url = new URL(req.url || '/', `http://127.0.0.1:${port}`);
|
|
36
|
+
if (url.pathname === '/callback') {
|
|
37
|
+
const code = url.searchParams.get('code');
|
|
38
|
+
if (code) {
|
|
39
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
40
|
+
res.end('<html><body><h2>Login successful!</h2><p>You can close this tab and return to your terminal.</p></body></html>');
|
|
41
|
+
server.close();
|
|
42
|
+
resolve({ code, port });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const error = url.searchParams.get('error_description') || url.searchParams.get('error') || 'Unknown error';
|
|
46
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
47
|
+
res.end(`<html><body><h2>Login failed</h2><p>${error}</p></body></html>`);
|
|
48
|
+
server.close();
|
|
49
|
+
reject(new Error(`OAuth callback error: ${error}`));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
res.writeHead(404);
|
|
54
|
+
res.end();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const timeout = setTimeout(() => {
|
|
58
|
+
server.close();
|
|
59
|
+
reject(new Error('Timed out waiting for login. Run `wayai login` again.'));
|
|
60
|
+
}, timeoutMs);
|
|
61
|
+
server.on('close', () => clearTimeout(timeout));
|
|
62
|
+
server.listen(port, '127.0.0.1');
|
|
63
|
+
server.on('error', (err) => {
|
|
64
|
+
if (err.code === 'EADDRINUSE') {
|
|
65
|
+
reject(new Error(`Port ${port} is in use. Try again.`));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
reject(err);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Find an available port by trying to listen on port 0
|
|
75
|
+
*/
|
|
76
|
+
export async function findAvailablePort() {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
const server = http.createServer();
|
|
79
|
+
server.listen(0, '127.0.0.1', () => {
|
|
80
|
+
const addr = server.address();
|
|
81
|
+
if (addr && typeof addr === 'object') {
|
|
82
|
+
const port = addr.port;
|
|
83
|
+
server.close(() => resolve(port));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
server.close(() => reject(new Error('Could not find available port')));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
server.on('error', reject);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Exchange PKCE authorization code for tokens
|
|
94
|
+
*/
|
|
95
|
+
export async function exchangeCodeForTokens(supabaseUrl, code, codeVerifier) {
|
|
96
|
+
const response = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=pkce`, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: { 'Content-Type': 'application/json' },
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
auth_code: code,
|
|
101
|
+
code_verifier: codeVerifier,
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const body = await response.text();
|
|
106
|
+
throw new Error(`Token exchange failed (${response.status}): ${body}`);
|
|
107
|
+
}
|
|
108
|
+
const data = await response.json();
|
|
109
|
+
return {
|
|
110
|
+
accessToken: data.access_token,
|
|
111
|
+
refreshToken: data.refresh_token,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Refresh an OAuth access token using a refresh token
|
|
116
|
+
*/
|
|
117
|
+
export async function refreshAccessToken(supabaseUrl, refreshToken) {
|
|
118
|
+
const response = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=refresh_token`, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: { 'Content-Type': 'application/json' },
|
|
121
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
122
|
+
});
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const body = await response.text();
|
|
125
|
+
throw new Error(`Token refresh failed (${response.status}): ${body}`);
|
|
126
|
+
}
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
return {
|
|
129
|
+
accessToken: data.access_token,
|
|
130
|
+
refreshToken: data.refresh_token,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Exchange MCP token for a JWT via the backend
|
|
135
|
+
*/
|
|
136
|
+
export async function exchangeMcpToken(apiUrl, mcpToken) {
|
|
137
|
+
const response = await fetch(`${apiUrl}/auth/mcp/exchange`, {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
headers: { 'Content-Type': 'application/json' },
|
|
140
|
+
body: JSON.stringify({ token: mcpToken }),
|
|
141
|
+
});
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
const body = await response.text();
|
|
144
|
+
throw new Error(`MCP token exchange failed (${response.status}): ${body}`);
|
|
145
|
+
}
|
|
146
|
+
const data = await response.json();
|
|
147
|
+
return data.access_token;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get a valid access token from the current config.
|
|
151
|
+
* Handles refresh for both OAuth and token auth methods.
|
|
152
|
+
*/
|
|
153
|
+
export async function getAccessToken(config) {
|
|
154
|
+
if (config.auth_method === 'oauth') {
|
|
155
|
+
if (!config.supabase_url || !config.refresh_token) {
|
|
156
|
+
throw new Error('Invalid OAuth config. Run `wayai login` again.');
|
|
157
|
+
}
|
|
158
|
+
const result = await refreshAccessToken(config.supabase_url, config.refresh_token);
|
|
159
|
+
// Update stored refresh token (it rotates)
|
|
160
|
+
const { writeConfig } = await import('./config.js');
|
|
161
|
+
writeConfig({ ...config, refresh_token: result.refreshToken });
|
|
162
|
+
return result.accessToken;
|
|
163
|
+
}
|
|
164
|
+
if (config.auth_method === 'token') {
|
|
165
|
+
if (!config.mcp_token) {
|
|
166
|
+
throw new Error('Invalid token config. Run `wayai login --token` again.');
|
|
167
|
+
}
|
|
168
|
+
return exchangeMcpToken(config.api_url, config.mcp_token);
|
|
169
|
+
}
|
|
170
|
+
throw new Error('Unknown auth method. Run `wayai login` again.');
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Read config and get access token, or exit with error.
|
|
174
|
+
*/
|
|
175
|
+
export async function requireAuth() {
|
|
176
|
+
const config = readConfig();
|
|
177
|
+
if (!config) {
|
|
178
|
+
console.error('Not logged in. Run `wayai login` first.');
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const accessToken = await getAccessToken(config);
|
|
183
|
+
return { config, accessToken };
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
console.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
187
|
+
console.error('Run `wayai login` to re-authenticate.');
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI configuration management — reads/writes ~/.wayai/config.json
|
|
3
|
+
*/
|
|
4
|
+
export interface CliConfig {
|
|
5
|
+
api_url: string;
|
|
6
|
+
auth_method: 'oauth' | 'token';
|
|
7
|
+
supabase_url?: string;
|
|
8
|
+
refresh_token?: string;
|
|
9
|
+
mcp_token?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function getConfigPath(): string;
|
|
12
|
+
export declare function readConfig(): CliConfig | null;
|
|
13
|
+
export declare function writeConfig(config: CliConfig): void;
|
|
14
|
+
export declare function deleteConfig(): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI configuration management — reads/writes ~/.wayai/config.json
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.wayai');
|
|
8
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
|
|
9
|
+
export function getConfigPath() {
|
|
10
|
+
return CONFIG_PATH;
|
|
11
|
+
}
|
|
12
|
+
export function readConfig() {
|
|
13
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
18
|
+
return JSON.parse(content);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function writeConfig(config) {
|
|
25
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
26
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', {
|
|
29
|
+
mode: 0o600, // owner-only read/write
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function deleteConfig() {
|
|
33
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
34
|
+
fs.unlinkSync(CONFIG_PATH);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAY9B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAiB;IAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;QACpE,IAAI,EAAE,KAAK,EAAE,wBAAwB;KACtC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colored terminal output from diff summary markdown
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Print a diff summary to the terminal with ANSI colors.
|
|
6
|
+
* Parses the markdown summary from the backend diff endpoint.
|
|
7
|
+
*/
|
|
8
|
+
export function printDiff(summary) {
|
|
9
|
+
const lines = summary.split('\n');
|
|
10
|
+
for (const line of lines) {
|
|
11
|
+
if (line.startsWith('**') && line.endsWith('**')) {
|
|
12
|
+
// Section header
|
|
13
|
+
console.log(`\n\x1b[1m${line.replace(/\*\*/g, '')}\x1b[0m`);
|
|
14
|
+
}
|
|
15
|
+
else if (line.trimStart().startsWith('+ ')) {
|
|
16
|
+
// Addition — green
|
|
17
|
+
console.log(`\x1b[32m${line}\x1b[0m`);
|
|
18
|
+
}
|
|
19
|
+
else if (line.trimStart().startsWith('- ')) {
|
|
20
|
+
// Deletion — red
|
|
21
|
+
console.log(`\x1b[31m${line}\x1b[0m`);
|
|
22
|
+
}
|
|
23
|
+
else if (line.trimStart().startsWith('~ ')) {
|
|
24
|
+
// Modification — yellow
|
|
25
|
+
console.log(`\x1b[33m${line}\x1b[0m`);
|
|
26
|
+
}
|
|
27
|
+
else if (line.includes('(no changes)')) {
|
|
28
|
+
// No changes — dim
|
|
29
|
+
console.log(`\x1b[2m${line}\x1b[0m`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(line);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
console.log(); // trailing newline
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=diff-display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-display.js","sourceRoot":"","sources":["../../src/lib/diff-display.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,iBAAiB;YACjB,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9D,CAAC;aAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,mBAAmB;YACnB,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,iBAAiB;YACjB,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,wBAAwB;YACxB,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,SAAS,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,mBAAmB;YACnB,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,SAAS,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,mBAAmB;AACpC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse wayai.yaml + agents/*.md into HubAsCodePayload.
|
|
3
|
+
* Synced with repositories/wayai/.github/actions/wayai-sync/src/parser.ts
|
|
4
|
+
*/
|
|
5
|
+
import type { HubAsCodePayload } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a hub folder into a HubAsCodePayload.
|
|
8
|
+
* Reads wayai.yaml and resolves agent `instructions` fields that reference
|
|
9
|
+
* .md files (relative paths under agents/) by inlining the file content.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseHubFolder(hubFolder: string): HubAsCodePayload;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse wayai.yaml + agents/*.md into HubAsCodePayload.
|
|
3
|
+
* Synced with repositories/wayai/.github/actions/wayai-sync/src/parser.ts
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as yaml from 'js-yaml';
|
|
8
|
+
/**
|
|
9
|
+
* Parse a hub folder into a HubAsCodePayload.
|
|
10
|
+
* Reads wayai.yaml and resolves agent `instructions` fields that reference
|
|
11
|
+
* .md files (relative paths under agents/) by inlining the file content.
|
|
12
|
+
*/
|
|
13
|
+
export function parseHubFolder(hubFolder) {
|
|
14
|
+
const yamlPath = path.join(hubFolder, 'wayai.yaml');
|
|
15
|
+
if (!fs.existsSync(yamlPath)) {
|
|
16
|
+
throw new Error(`wayai.yaml not found in ${hubFolder}`);
|
|
17
|
+
}
|
|
18
|
+
const yamlContent = fs.readFileSync(yamlPath, 'utf-8');
|
|
19
|
+
const config = yaml.load(yamlContent);
|
|
20
|
+
if (!config || typeof config !== 'object') {
|
|
21
|
+
throw new Error(`Invalid YAML in ${yamlPath}`);
|
|
22
|
+
}
|
|
23
|
+
if (!config.hub_id) {
|
|
24
|
+
throw new Error(`Missing hub_id in ${yamlPath}`);
|
|
25
|
+
}
|
|
26
|
+
if (!config.hub_environment) {
|
|
27
|
+
throw new Error(`Missing hub_environment in ${yamlPath}`);
|
|
28
|
+
}
|
|
29
|
+
// Resolve agent instructions from .md files
|
|
30
|
+
// Synced with repositories/wayai/.github/actions/wayai-sync/src/parser.ts
|
|
31
|
+
const agents = config.agents?.map((agent) => {
|
|
32
|
+
const resolved = { ...agent };
|
|
33
|
+
if (typeof resolved.instructions === 'string' && resolved.instructions.endsWith('.md')) {
|
|
34
|
+
// Instructions can be either:
|
|
35
|
+
// "agents/pilot.md" (relative to hubFolder — standard format per workspace-format.md)
|
|
36
|
+
// "pilot.md" (legacy — just filename, looked up under agents/)
|
|
37
|
+
const instrValue = resolved.instructions;
|
|
38
|
+
const instructionsPath = instrValue.startsWith('agents/')
|
|
39
|
+
? path.join(hubFolder, instrValue)
|
|
40
|
+
: path.join(hubFolder, 'agents', instrValue);
|
|
41
|
+
if (fs.existsSync(instructionsPath)) {
|
|
42
|
+
resolved.instructions = fs.readFileSync(instructionsPath, 'utf-8');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
throw new Error(`Agent instructions file not found: ${instructionsPath} (referenced by agent "${agent.name}")`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return resolved;
|
|
49
|
+
});
|
|
50
|
+
const payload = {
|
|
51
|
+
version: config.version || 1,
|
|
52
|
+
hub_id: config.hub_id,
|
|
53
|
+
hub_environment: config.hub_environment,
|
|
54
|
+
hub: config.hub,
|
|
55
|
+
};
|
|
56
|
+
if (agents && agents.length > 0) {
|
|
57
|
+
payload.agents = agents;
|
|
58
|
+
}
|
|
59
|
+
if (config.states && config.states.length > 0) {
|
|
60
|
+
payload.states = config.states;
|
|
61
|
+
}
|
|
62
|
+
return payload;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/lib/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the CLI — mirrors backend CI types
|
|
3
|
+
*/
|
|
4
|
+
export interface HubAsCodePayload {
|
|
5
|
+
version: number;
|
|
6
|
+
hub_id: string;
|
|
7
|
+
hub_environment: string;
|
|
8
|
+
hub: {
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
hub_type?: string;
|
|
12
|
+
ai_mode?: string;
|
|
13
|
+
timezone?: string;
|
|
14
|
+
app_permission?: string;
|
|
15
|
+
non_app_permission?: string;
|
|
16
|
+
mcp_access?: string;
|
|
17
|
+
file_handling_mode?: string;
|
|
18
|
+
max_file_size_for_attachment?: number;
|
|
19
|
+
inactivity_interval?: number;
|
|
20
|
+
followup_message?: string;
|
|
21
|
+
hub_sla?: Record<string, number>;
|
|
22
|
+
kanban_statuses?: Array<{
|
|
23
|
+
name: string;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
agents?: HubAsCodeAgent[];
|
|
27
|
+
states?: HubAsCodeState[];
|
|
28
|
+
connections?: Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
type: string;
|
|
31
|
+
service?: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export interface HubAsCodeAgent {
|
|
35
|
+
name: string;
|
|
36
|
+
role: string;
|
|
37
|
+
connection: string;
|
|
38
|
+
instructions?: string;
|
|
39
|
+
enabled?: boolean;
|
|
40
|
+
include_message_timestamps?: boolean;
|
|
41
|
+
settings?: Record<string, unknown>;
|
|
42
|
+
response_format?: {
|
|
43
|
+
type: string;
|
|
44
|
+
schema_name: string;
|
|
45
|
+
schema_json: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
tools?: {
|
|
48
|
+
native?: string[];
|
|
49
|
+
delegation?: Array<{
|
|
50
|
+
type: string;
|
|
51
|
+
tool: string;
|
|
52
|
+
target: string;
|
|
53
|
+
}>;
|
|
54
|
+
custom?: HubAsCodeCustomTool[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export interface HubAsCodeCustomTool {
|
|
58
|
+
name: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
method?: string;
|
|
61
|
+
path?: string;
|
|
62
|
+
body_format?: string;
|
|
63
|
+
connection?: string;
|
|
64
|
+
headers?: Record<string, unknown>;
|
|
65
|
+
query_params?: Record<string, unknown>;
|
|
66
|
+
body_params?: Record<string, unknown>;
|
|
67
|
+
instructions?: string;
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface HubAsCodeState {
|
|
71
|
+
name: string;
|
|
72
|
+
scope: string;
|
|
73
|
+
description?: string;
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
json_schema?: Record<string, unknown>;
|
|
76
|
+
initial_value?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
export interface CiDiffResponse {
|
|
79
|
+
has_changes: boolean;
|
|
80
|
+
direction: 'push' | 'pull';
|
|
81
|
+
summary: string;
|
|
82
|
+
diff: unknown;
|
|
83
|
+
}
|
|
84
|
+
export interface CiLookupResponse {
|
|
85
|
+
hub_id: string;
|
|
86
|
+
hub_name: string;
|
|
87
|
+
hub_environment: string;
|
|
88
|
+
project_name: string;
|
|
89
|
+
organization_name: string;
|
|
90
|
+
}
|
|
91
|
+
export interface CiSyncResponse {
|
|
92
|
+
preview_hub_id: string;
|
|
93
|
+
created: boolean;
|
|
94
|
+
changes: {
|
|
95
|
+
hub_updated: boolean;
|
|
96
|
+
agents_created: number;
|
|
97
|
+
agents_updated: number;
|
|
98
|
+
agents_deleted: number;
|
|
99
|
+
tools_created: number;
|
|
100
|
+
tools_updated: number;
|
|
101
|
+
tools_deleted: number;
|
|
102
|
+
states_created: number;
|
|
103
|
+
states_updated: number;
|
|
104
|
+
states_deleted: number;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility functions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Slugify a string: lowercase, normalize accents, replace non-alphanumeric with hyphens.
|
|
6
|
+
* Matches the slugification rules from workspace-format.md
|
|
7
|
+
*/
|
|
8
|
+
export declare function slugify(input: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Try to detect hub_id from wayai.yaml in the current working directory.
|
|
11
|
+
* Returns null if no wayai.yaml exists or it lacks hub_id.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectHubFromCwd(): Promise<{
|
|
14
|
+
hubId: string;
|
|
15
|
+
hubFolder: string;
|
|
16
|
+
} | null>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility functions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Slugify a string: lowercase, normalize accents, replace non-alphanumeric with hyphens.
|
|
6
|
+
* Matches the slugification rules from workspace-format.md
|
|
7
|
+
*/
|
|
8
|
+
export function slugify(input) {
|
|
9
|
+
return input
|
|
10
|
+
.normalize('NFD')
|
|
11
|
+
.replace(/[\u0300-\u036f]/g, '') // strip diacritics
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9]+/g, '-') // non-alphanumeric → hyphens
|
|
14
|
+
.replace(/-+/g, '-') // collapse consecutive
|
|
15
|
+
.replace(/^-|-$/g, '') // trim leading/trailing
|
|
16
|
+
.slice(0, 50); // limit length
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Try to detect hub_id from wayai.yaml in the current working directory.
|
|
20
|
+
* Returns null if no wayai.yaml exists or it lacks hub_id.
|
|
21
|
+
*/
|
|
22
|
+
export async function detectHubFromCwd() {
|
|
23
|
+
const fs = await import('node:fs');
|
|
24
|
+
const path = await import('node:path');
|
|
25
|
+
const yaml = await import('js-yaml');
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
// Check current directory
|
|
28
|
+
const yamlPath = path.join(cwd, 'wayai.yaml');
|
|
29
|
+
if (fs.existsSync(yamlPath)) {
|
|
30
|
+
const content = fs.readFileSync(yamlPath, 'utf-8');
|
|
31
|
+
const config = yaml.load(content);
|
|
32
|
+
if (config?.hub_id && typeof config.hub_id === 'string') {
|
|
33
|
+
return { hubId: config.hub_id, hubFolder: cwd };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,mBAAmB;SACnD,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAI,6BAA6B;SAC5D,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAY,uBAAuB;SACtD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAU,wBAAwB;SACvD,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAkB,eAAe;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAErC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAwC,CAAC;QACzE,IAAI,MAAM,EAAE,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML writer — converts HubAsCodePayload to wayai.yaml + agents/*.md files
|
|
3
|
+
* Reverse of parser.ts
|
|
4
|
+
*/
|
|
5
|
+
import type { HubAsCodePayload } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Write a HubAsCodePayload to disk as wayai.yaml + agents/*.md files.
|
|
8
|
+
*
|
|
9
|
+
* - Creates `wayai.yaml` with `instructions:` referencing agent .md file paths
|
|
10
|
+
* - Creates `agents/<slug>.md` for each agent with instructions
|
|
11
|
+
* - Removes orphan .md files in agents/ that don't match any current agent
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeHubFolder(hubFolder: string, payload: HubAsCodePayload): void;
|