@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.
Files changed (43) hide show
  1. package/dist/commands/login.d.ts +4 -0
  2. package/dist/commands/login.js +123 -0
  3. package/dist/commands/login.js.map +1 -0
  4. package/dist/commands/logout.d.ts +4 -0
  5. package/dist/commands/logout.js +14 -0
  6. package/dist/commands/logout.js.map +1 -0
  7. package/dist/commands/pull.d.ts +4 -0
  8. package/dist/commands/pull.js +73 -0
  9. package/dist/commands/pull.js.map +1 -0
  10. package/dist/commands/push.d.ts +4 -0
  11. package/dist/commands/push.js +90 -0
  12. package/dist/commands/push.js.map +1 -0
  13. package/dist/commands/status.d.ts +4 -0
  14. package/dist/commands/status.js +26 -0
  15. package/dist/commands/status.js.map +1 -0
  16. package/dist/index.d.ts +13 -0
  17. package/dist/index.js +90 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lib/api-client.d.ts +18 -0
  20. package/dist/lib/api-client.js +50 -0
  21. package/dist/lib/api-client.js.map +1 -0
  22. package/dist/lib/auth.d.ts +59 -0
  23. package/dist/lib/auth.js +191 -0
  24. package/dist/lib/auth.js.map +1 -0
  25. package/dist/lib/config.d.ts +14 -0
  26. package/dist/lib/config.js +37 -0
  27. package/dist/lib/config.js.map +1 -0
  28. package/dist/lib/diff-display.d.ts +8 -0
  29. package/dist/lib/diff-display.js +37 -0
  30. package/dist/lib/diff-display.js.map +1 -0
  31. package/dist/lib/parser.d.ts +11 -0
  32. package/dist/lib/parser.js +64 -0
  33. package/dist/lib/parser.js.map +1 -0
  34. package/dist/lib/types.d.ts +106 -0
  35. package/dist/lib/types.js +5 -0
  36. package/dist/lib/types.js.map +1 -0
  37. package/dist/lib/utils.d.ts +16 -0
  38. package/dist/lib/utils.js +38 -0
  39. package/dist/lib/utils.js.map +1 -0
  40. package/dist/lib/yaml-writer.d.ts +13 -0
  41. package/dist/lib/yaml-writer.js +101 -0
  42. package/dist/lib/yaml-writer.js.map +1 -0
  43. package/package.json +41 -0
@@ -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,8 @@
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 declare function printDiff(summary: string): void;
@@ -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,5 @@
1
+ /**
2
+ * Shared types for the CLI — mirrors backend CI types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -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;