@wayai/cli 0.1.0 → 0.2.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 (44) hide show
  1. package/dist/commands/init.d.ts +7 -0
  2. package/dist/commands/init.js +88 -0
  3. package/dist/commands/init.js.map +1 -0
  4. package/dist/commands/login.d.ts +1 -0
  5. package/dist/commands/login.js +54 -13
  6. package/dist/commands/login.js.map +1 -1
  7. package/dist/commands/pull.d.ts +7 -1
  8. package/dist/commands/pull.js +134 -42
  9. package/dist/commands/pull.js.map +1 -1
  10. package/dist/commands/push.d.ts +6 -1
  11. package/dist/commands/push.js +248 -54
  12. package/dist/commands/push.js.map +1 -1
  13. package/dist/commands/status.d.ts +1 -1
  14. package/dist/commands/status.js +17 -8
  15. package/dist/commands/status.js.map +1 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +24 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/lib/api-client.d.ts +3 -1
  20. package/dist/lib/api-client.js +9 -0
  21. package/dist/lib/api-client.js.map +1 -1
  22. package/dist/lib/auth.d.ts +13 -4
  23. package/dist/lib/auth.js +52 -12
  24. package/dist/lib/auth.js.map +1 -1
  25. package/dist/lib/config.d.ts +2 -0
  26. package/dist/lib/config.js.map +1 -1
  27. package/dist/lib/parser.js +13 -3
  28. package/dist/lib/parser.js.map +1 -1
  29. package/dist/lib/repo-config.d.ts +16 -0
  30. package/dist/lib/repo-config.js +49 -0
  31. package/dist/lib/repo-config.js.map +1 -0
  32. package/dist/lib/types.d.ts +13 -0
  33. package/dist/lib/utils.d.ts +4 -0
  34. package/dist/lib/utils.js +13 -0
  35. package/dist/lib/utils.js.map +1 -1
  36. package/dist/lib/workspace.d.ts +75 -0
  37. package/dist/lib/workspace.js +244 -0
  38. package/dist/lib/workspace.js.map +1 -0
  39. package/dist/lib/workspace.test.d.ts +5 -0
  40. package/dist/lib/workspace.test.js +329 -0
  41. package/dist/lib/workspace.test.js.map +1 -0
  42. package/dist/lib/yaml-writer.js +10 -6
  43. package/dist/lib/yaml-writer.js.map +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Workspace detection and hub resolution for workspace-aware CLI commands.
3
+ *
4
+ * A workspace is a `workspace/` directory at the git root containing
5
+ * project/hub folders, each with a wayai.yaml file.
6
+ */
7
+ import { execFileSync } from 'node:child_process';
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import * as yaml from 'js-yaml';
11
+ import { slugify } from './utils.js';
12
+ /**
13
+ * Find the git repository root. Returns null if not inside a git repo.
14
+ */
15
+ export function findGitRoot() {
16
+ try {
17
+ return execFileSync('git', ['rev-parse', '--show-toplevel'], {
18
+ encoding: 'utf-8',
19
+ stdio: ['pipe', 'pipe', 'pipe'],
20
+ }).trim();
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ /**
27
+ * Detect the workspace directory ({gitRoot}/workspace/).
28
+ * Returns null if not in a git repo or workspace/ doesn't exist.
29
+ */
30
+ export function detectWorkspace() {
31
+ const gitRoot = findGitRoot();
32
+ if (!gitRoot)
33
+ return null;
34
+ const workspaceDir = path.join(gitRoot, 'workspace');
35
+ if (!fs.existsSync(workspaceDir) || !fs.statSync(workspaceDir).isDirectory()) {
36
+ return null;
37
+ }
38
+ return { gitRoot, workspaceDir };
39
+ }
40
+ /**
41
+ * Read hub metadata from a wayai.yaml file.
42
+ * Returns null if the file doesn't exist or lacks required fields.
43
+ */
44
+ function readHubYaml(yamlPath) {
45
+ if (!fs.existsSync(yamlPath))
46
+ return null;
47
+ try {
48
+ const content = fs.readFileSync(yamlPath, 'utf-8');
49
+ const config = yaml.load(content);
50
+ if (!config?.hub_id || !config.hub_environment)
51
+ return null;
52
+ return { hubId: config.hub_id, hubEnvironment: config.hub_environment };
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ /**
59
+ * Scan the workspace directory for hub folders (2 levels: project/hub).
60
+ * Returns metadata for each hub that has a valid wayai.yaml.
61
+ */
62
+ export function scanWorkspaceHubs(workspaceDir) {
63
+ const hubs = [];
64
+ const projects = safeReaddir(workspaceDir);
65
+ for (const project of projects) {
66
+ const projectDir = path.join(workspaceDir, project);
67
+ if (!isDirectory(projectDir))
68
+ continue;
69
+ const hubDirs = safeReaddir(projectDir);
70
+ for (const hub of hubDirs) {
71
+ const hubFolder = path.join(projectDir, hub);
72
+ if (!isDirectory(hubFolder))
73
+ continue;
74
+ const meta = readHubYaml(path.join(hubFolder, 'wayai.yaml'));
75
+ if (meta) {
76
+ hubs.push({ hubFolder, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
77
+ }
78
+ }
79
+ }
80
+ return hubs;
81
+ }
82
+ /**
83
+ * Compute the hub folder slug with preview disambiguation.
84
+ * Production: slugify(hubName)
85
+ * Preview: slugify(hubName) + "-" + slugify(previewLabel || branchName || hubId[0:8])
86
+ *
87
+ * IMPORTANT: This must produce identical output to the backend's computeHubSlug
88
+ * in workers/backend/src/routes/api/ci/lookup.ts. If either changes, update both.
89
+ */
90
+ export function getHubFolderSlug(hubName, hubEnvironment, hubId, previewLabel, branchName) {
91
+ const base = slugify(hubName);
92
+ if (hubEnvironment !== 'preview')
93
+ return base;
94
+ const suffix = previewLabel || branchName || hubId.slice(0, 8);
95
+ return `${base}-${slugify(suffix)}`;
96
+ }
97
+ /**
98
+ * Resolve a hub folder in the workspace by hub_id match (handles folder renames),
99
+ * falling back to slugified project/hub path with preview disambiguation.
100
+ */
101
+ export function resolveHubFolder(workspaceDir, hubId, projectName, hubName, hubEnvironment, previewLabel, branchName) {
102
+ // First: try to find by hub_id match (handles folder renames)
103
+ if (hubId) {
104
+ const allHubs = scanWorkspaceHubs(workspaceDir);
105
+ const match = allHubs.find((h) => h.hubId === hubId);
106
+ if (match)
107
+ return match.hubFolder;
108
+ }
109
+ // Fallback: slugified path with preview disambiguation
110
+ const hubFolderSlug = getHubFolderSlug(hubName, hubEnvironment, hubId || '', previewLabel, branchName);
111
+ return path.join(workspaceDir, slugify(projectName), hubFolderSlug);
112
+ }
113
+ /**
114
+ * Get hub folders with uncommitted changes via `git status`.
115
+ * Filters to wayai.yaml and agents/*.md files under workspace/.
116
+ * Unlike the GitHub Action, does NOT filter by hub_environment.
117
+ */
118
+ export function getChangedHubs(workspaceDir) {
119
+ const gitRoot = findGitRoot();
120
+ if (!gitRoot)
121
+ return [];
122
+ // Get workspace path relative to git root for the git status query
123
+ const relWorkspace = path.relative(gitRoot, workspaceDir);
124
+ // Ensure the workspace is inside the git root (no path traversal)
125
+ const normalizedRel = path.normalize(relWorkspace);
126
+ if (normalizedRel.startsWith('..') || path.isAbsolute(normalizedRel)) {
127
+ return [];
128
+ }
129
+ let statusOutput;
130
+ try {
131
+ statusOutput = execFileSync('git', ['status', '--porcelain', '-u', '--', `${relWorkspace}/`], {
132
+ encoding: 'utf-8',
133
+ cwd: gitRoot,
134
+ stdio: ['pipe', 'pipe', 'pipe'],
135
+ });
136
+ }
137
+ catch {
138
+ return [];
139
+ }
140
+ // Split into lines, preserving leading spaces (porcelain status prefix uses them)
141
+ const lines = statusOutput.split('\n').filter((l) => l.length > 0);
142
+ // Extract file paths from porcelain output (skip the 2-char status + space prefix)
143
+ const changedFiles = lines.map((line) => {
144
+ // Porcelain format: "XY file" or "XY orig -> file" (for renames)
145
+ const filePart = line.slice(3);
146
+ // Handle renames: "orig -> dest"
147
+ const arrowIdx = filePart.indexOf(' -> ');
148
+ return arrowIdx >= 0 ? filePart.slice(arrowIdx + 4) : filePart;
149
+ });
150
+ // Filter to hub config files
151
+ const hubFiles = changedFiles.filter((file) => {
152
+ return file.endsWith('/wayai.yaml') || file.endsWith('wayai.yaml') || /\/agents\/[^/]+\.md$/.test(file);
153
+ });
154
+ if (hubFiles.length === 0)
155
+ return [];
156
+ // Extract unique hub folder paths (absolute)
157
+ const hubFolders = new Set();
158
+ for (const file of hubFiles) {
159
+ const absFile = path.resolve(gitRoot, file);
160
+ if (file.endsWith('wayai.yaml')) {
161
+ hubFolders.add(path.dirname(absFile));
162
+ }
163
+ else if (file.includes('/agents/')) {
164
+ const agentsIndex = absFile.lastIndexOf('/agents/');
165
+ hubFolders.add(absFile.substring(0, agentsIndex));
166
+ }
167
+ }
168
+ // Read each hub folder's wayai.yaml
169
+ const hubs = [];
170
+ for (const hubFolder of hubFolders) {
171
+ const meta = readHubYaml(path.join(hubFolder, 'wayai.yaml'));
172
+ if (meta) {
173
+ hubs.push({ hubFolder, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
174
+ }
175
+ }
176
+ return hubs;
177
+ }
178
+ /**
179
+ * Parse a hub path (project/hub or org/project/hub), resolve it locally if possible,
180
+ * and return the parsed segments for API fallback if local resolution fails.
181
+ *
182
+ * Returns `{ resolved }` if found locally, or `{ segments }` for API lookup.
183
+ */
184
+ export function resolveExplicitHubPath(hubPath) {
185
+ const parts = hubPath.split('/');
186
+ let projectSegment;
187
+ let hubSegment;
188
+ let orgPrefix;
189
+ if (parts.length === 2) {
190
+ [projectSegment, hubSegment] = parts;
191
+ }
192
+ else if (parts.length === 3) {
193
+ [orgPrefix, projectSegment, hubSegment] = parts;
194
+ }
195
+ else {
196
+ throw new Error('Hub path must be project/hub or org/project/hub');
197
+ }
198
+ // Try local workspace resolution first (avoids API call, handles slugified folder names)
199
+ const workspace = detectWorkspace();
200
+ if (workspace) {
201
+ const local = findHubByFolderPath(workspace.workspaceDir, projectSegment, hubSegment);
202
+ if (local) {
203
+ return {
204
+ resolved: {
205
+ hubId: local.hubId,
206
+ hubFolder: local.hubFolder,
207
+ hubEnvironment: local.hubEnvironment,
208
+ },
209
+ };
210
+ }
211
+ }
212
+ return { segments: { orgPrefix, project: projectSegment, hub: hubSegment } };
213
+ }
214
+ /**
215
+ * Find a hub in the workspace by matching project/hub folder names.
216
+ * Accepts the 2-part path (project/hub) as it appears on disk.
217
+ * Returns the hub location if a matching folder with valid wayai.yaml exists.
218
+ */
219
+ export function findHubByFolderPath(workspaceDir, projectFolder, hubFolder) {
220
+ const candidate = path.join(workspaceDir, projectFolder, hubFolder);
221
+ if (!isDirectory(candidate))
222
+ return null;
223
+ const meta = readHubYaml(path.join(candidate, 'wayai.yaml'));
224
+ if (!meta)
225
+ return null;
226
+ return { hubFolder: candidate, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment };
227
+ }
228
+ function isDirectory(p) {
229
+ try {
230
+ return fs.statSync(p).isDirectory();
231
+ }
232
+ catch {
233
+ return false;
234
+ }
235
+ }
236
+ function safeReaddir(dir) {
237
+ try {
238
+ return fs.readdirSync(dir).filter((entry) => !entry.startsWith('.'));
239
+ }
240
+ catch {
241
+ return [];
242
+ }
243
+ }
244
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/lib/workspace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAarC;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE;YAC3D,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAA8D,CAAC;QAC/F,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe;YAAE,OAAO,IAAI,CAAC;QAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAoB;IACpD,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;YAAE,SAAS;QAEvC,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAC7C,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;gBAAE,SAAS;YAEtC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;YAC7D,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,cAAsB,EACtB,KAAa,EACb,YAA4B,EAC5B,UAA0B;IAE1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC9C,MAAM,MAAM,GAAG,YAAY,IAAI,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAoB,EACpB,KAAyB,EACzB,WAAmB,EACnB,OAAe,EACf,cAAsB,EACtB,YAA4B,EAC5B,UAA0B;IAE1B,8DAA8D;IAC9D,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACrD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,SAAS,CAAC;IACpC,CAAC;IAED,uDAAuD;IACvD,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IACvG,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB;IACjD,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAExB,mEAAmE;IACnE,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE1D,kEAAkE;IAClE,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACrE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,YAAY,GAAG,CAAC,EAAE;YAC5F,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,kFAAkF;IAClF,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnE,mFAAmF;IACnF,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACtC,iEAAiE;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,iCAAiC;QACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC5C,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1G,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,6CAA6C;IAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACpD,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QAC7D,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAe;IAEf,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEjC,IAAI,cAAsB,CAAC;IAC3B,IAAI,UAAkB,CAAC;IACvB,IAAI,SAA6B,CAAC;IAElC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;IACvC,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,CAAC,SAAS,EAAE,cAAc,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;IAClD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,yFAAyF;IACzF,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;IACpC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,mBAAmB,CAAC,SAAS,CAAC,YAAY,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QACtF,IAAI,KAAK,EAAE,CAAC;YACV,OAAO;gBACL,QAAQ,EAAE;oBACR,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,cAAc,EAAE,KAAK,CAAC,cAAc;iBACrC;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,CAAC;AAC/E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,aAAqB,EACrB,SAAiB;IAEjB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAC7D,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;AAC1F,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC5B,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Unit tests for resolveExplicitHubPath and findHubByFolderPath
3
+ * using vi.mock to mock filesystem and child_process dependencies.
4
+ */
5
+ export {};
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Unit tests for resolveExplicitHubPath and findHubByFolderPath
3
+ * using vi.mock to mock filesystem and child_process dependencies.
4
+ */
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import * as path from 'node:path';
7
+ // ---------------------------------------------------------------------------
8
+ // Mocks
9
+ // ---------------------------------------------------------------------------
10
+ vi.mock('node:fs', () => ({
11
+ existsSync: vi.fn(),
12
+ statSync: vi.fn(),
13
+ readFileSync: vi.fn(),
14
+ readdirSync: vi.fn(),
15
+ }));
16
+ vi.mock('node:child_process', () => ({
17
+ execFileSync: vi.fn(),
18
+ }));
19
+ // Import after mocks are set up
20
+ import * as fs from 'node:fs';
21
+ import { execFileSync } from 'node:child_process';
22
+ import { resolveExplicitHubPath, findHubByFolderPath } from './workspace.js';
23
+ const mockExistsSync = vi.mocked(fs.existsSync);
24
+ const mockStatSync = vi.mocked(fs.statSync);
25
+ const mockReadFileSync = vi.mocked(fs.readFileSync);
26
+ const mockExecFileSync = vi.mocked(execFileSync);
27
+ // ---------------------------------------------------------------------------
28
+ // Helpers
29
+ // ---------------------------------------------------------------------------
30
+ const VALID_WAYAI_YAML = `hub_id: "hub-abc-123"
31
+ hub_environment: production
32
+ hub:
33
+ name: Test Hub
34
+ `;
35
+ // ---------------------------------------------------------------------------
36
+ // Tests: findHubByFolderPath
37
+ // ---------------------------------------------------------------------------
38
+ describe('findHubByFolderPath', () => {
39
+ beforeEach(() => {
40
+ vi.resetAllMocks();
41
+ });
42
+ it('returns HubLocation when folder exists with valid wayai.yaml', () => {
43
+ const workspaceDir = '/workspace';
44
+ const candidate = path.join(workspaceDir, 'my-project', 'my-hub');
45
+ const yamlPath = path.join(candidate, 'wayai.yaml');
46
+ // Mock the directory check (isDirectory via statSync)
47
+ mockStatSync.mockImplementation((p) => {
48
+ if (p === candidate) {
49
+ return { isDirectory: () => true };
50
+ }
51
+ throw new Error(`ENOENT: ${String(p)}`);
52
+ });
53
+ // Mock wayai.yaml existence and content
54
+ mockExistsSync.mockImplementation((p) => p === yamlPath);
55
+ mockReadFileSync.mockImplementation((p) => {
56
+ if (p === yamlPath)
57
+ return VALID_WAYAI_YAML;
58
+ throw new Error(`ENOENT: ${String(p)}`);
59
+ });
60
+ const result = findHubByFolderPath(workspaceDir, 'my-project', 'my-hub');
61
+ expect(result).not.toBeNull();
62
+ expect(result.hubId).toBe('hub-abc-123');
63
+ expect(result.hubEnvironment).toBe('production');
64
+ expect(result.hubFolder).toBe(candidate);
65
+ });
66
+ it('returns null when folder does not exist', () => {
67
+ mockStatSync.mockImplementation(() => {
68
+ throw new Error('ENOENT');
69
+ });
70
+ const result = findHubByFolderPath('/workspace', 'project', 'nonexistent-hub');
71
+ expect(result).toBeNull();
72
+ });
73
+ it('returns null when folder exists but has no wayai.yaml', () => {
74
+ const workspaceDir = '/workspace';
75
+ const candidate = path.join(workspaceDir, 'project', 'hub-no-yaml');
76
+ const yamlPath = path.join(candidate, 'wayai.yaml');
77
+ mockStatSync.mockImplementation((p) => {
78
+ if (p === candidate) {
79
+ return { isDirectory: () => true };
80
+ }
81
+ throw new Error(`ENOENT: ${String(p)}`);
82
+ });
83
+ // wayai.yaml does not exist
84
+ mockExistsSync.mockImplementation(() => false);
85
+ const result = findHubByFolderPath(workspaceDir, 'project', 'hub-no-yaml');
86
+ expect(result).toBeNull();
87
+ });
88
+ it('returns null when wayai.yaml exists but lacks hub_id', () => {
89
+ const workspaceDir = '/workspace';
90
+ const candidate = path.join(workspaceDir, 'project', 'bad-hub');
91
+ const yamlPath = path.join(candidate, 'wayai.yaml');
92
+ mockStatSync.mockImplementation((p) => {
93
+ if (p === candidate) {
94
+ return { isDirectory: () => true };
95
+ }
96
+ throw new Error(`ENOENT: ${String(p)}`);
97
+ });
98
+ mockExistsSync.mockImplementation((p) => p === yamlPath);
99
+ mockReadFileSync.mockImplementation((p) => {
100
+ if (p === yamlPath)
101
+ return 'hub_environment: preview\nhub:\n name: Bad\n';
102
+ throw new Error(`ENOENT: ${String(p)}`);
103
+ });
104
+ const result = findHubByFolderPath(workspaceDir, 'project', 'bad-hub');
105
+ expect(result).toBeNull();
106
+ });
107
+ it('returns null when wayai.yaml has invalid YAML', () => {
108
+ const workspaceDir = '/workspace';
109
+ const candidate = path.join(workspaceDir, 'project', 'bad-yaml');
110
+ const yamlPath = path.join(candidate, 'wayai.yaml');
111
+ mockStatSync.mockImplementation((p) => {
112
+ if (p === candidate) {
113
+ return { isDirectory: () => true };
114
+ }
115
+ throw new Error(`ENOENT: ${String(p)}`);
116
+ });
117
+ mockExistsSync.mockImplementation((p) => p === yamlPath);
118
+ mockReadFileSync.mockImplementation((p) => {
119
+ if (p === yamlPath)
120
+ return '{{{{ invalid yaml';
121
+ throw new Error(`ENOENT: ${String(p)}`);
122
+ });
123
+ const result = findHubByFolderPath(workspaceDir, 'project', 'bad-yaml');
124
+ expect(result).toBeNull();
125
+ });
126
+ it('returns preview environment when wayai.yaml specifies preview', () => {
127
+ const workspaceDir = '/workspace';
128
+ const candidate = path.join(workspaceDir, 'project', 'preview-hub');
129
+ const yamlPath = path.join(candidate, 'wayai.yaml');
130
+ mockStatSync.mockImplementation((p) => {
131
+ if (p === candidate) {
132
+ return { isDirectory: () => true };
133
+ }
134
+ throw new Error(`ENOENT: ${String(p)}`);
135
+ });
136
+ const previewYaml = `hub_id: "hub-preview-1"
137
+ hub_environment: preview
138
+ hub:
139
+ name: Preview Hub
140
+ `;
141
+ mockExistsSync.mockImplementation((p) => p === yamlPath);
142
+ mockReadFileSync.mockImplementation((p) => {
143
+ if (p === yamlPath)
144
+ return previewYaml;
145
+ throw new Error(`ENOENT: ${String(p)}`);
146
+ });
147
+ const result = findHubByFolderPath(workspaceDir, 'project', 'preview-hub');
148
+ expect(result).not.toBeNull();
149
+ expect(result.hubId).toBe('hub-preview-1');
150
+ expect(result.hubEnvironment).toBe('preview');
151
+ });
152
+ });
153
+ // ---------------------------------------------------------------------------
154
+ // Tests: resolveExplicitHubPath
155
+ // ---------------------------------------------------------------------------
156
+ describe('resolveExplicitHubPath', () => {
157
+ beforeEach(() => {
158
+ vi.resetAllMocks();
159
+ });
160
+ /**
161
+ * Helper: configure mocks so detectWorkspace() returns null
162
+ * (no git root or no workspace/ directory).
163
+ */
164
+ function mockNoWorkspace() {
165
+ // execFileSync for git rev-parse throws (not in a git repo)
166
+ mockExecFileSync.mockImplementation(() => {
167
+ throw new Error('not a git repository');
168
+ });
169
+ }
170
+ /**
171
+ * Helper: configure mocks so detectWorkspace() finds a workspace at the given root.
172
+ */
173
+ function mockWorkspaceAt(gitRoot) {
174
+ const workspaceDir = path.join(gitRoot, 'workspace');
175
+ // execFileSync for git rev-parse returns the gitRoot
176
+ mockExecFileSync.mockReturnValue(gitRoot + '\n');
177
+ // workspace dir exists and is a directory
178
+ mockExistsSync.mockImplementation((p) => {
179
+ if (p === workspaceDir)
180
+ return true;
181
+ return false;
182
+ });
183
+ mockStatSync.mockImplementation((p) => {
184
+ if (p === workspaceDir) {
185
+ return { isDirectory: () => true };
186
+ }
187
+ throw new Error(`ENOENT: ${String(p)}`);
188
+ });
189
+ }
190
+ it('throws Error for invalid path with 1 segment', () => {
191
+ mockNoWorkspace();
192
+ expect(() => resolveExplicitHubPath('just-one-segment')).toThrow('Hub path must be project/hub or org/project/hub');
193
+ });
194
+ it('throws Error for invalid path with 4 segments', () => {
195
+ mockNoWorkspace();
196
+ expect(() => resolveExplicitHubPath('a/b/c/d')).toThrow('Hub path must be project/hub or org/project/hub');
197
+ });
198
+ it('throws Error for empty path (0 segments)', () => {
199
+ mockNoWorkspace();
200
+ // Empty string split by '/' gives [''] which has length 1
201
+ expect(() => resolveExplicitHubPath('')).toThrow('Hub path must be project/hub or org/project/hub');
202
+ });
203
+ it('returns segments for 2-part path when no workspace exists', () => {
204
+ mockNoWorkspace();
205
+ const result = resolveExplicitHubPath('my-project/my-hub');
206
+ expect('segments' in result).toBe(true);
207
+ if ('segments' in result) {
208
+ expect(result.segments.project).toBe('my-project');
209
+ expect(result.segments.hub).toBe('my-hub');
210
+ expect(result.segments.orgPrefix).toBeUndefined();
211
+ }
212
+ });
213
+ it('returns segments for 3-part path (org/project/hub)', () => {
214
+ mockNoWorkspace();
215
+ const result = resolveExplicitHubPath('my-org/my-project/my-hub');
216
+ expect('segments' in result).toBe(true);
217
+ if ('segments' in result) {
218
+ expect(result.segments.orgPrefix).toBe('my-org');
219
+ expect(result.segments.project).toBe('my-project');
220
+ expect(result.segments.hub).toBe('my-hub');
221
+ }
222
+ });
223
+ it('returns segments for 2-part path when workspace exists but hub not found locally', () => {
224
+ const gitRoot = '/home/user/repo';
225
+ mockWorkspaceAt(gitRoot);
226
+ // findHubByFolderPath will call statSync on the candidate path, which will
227
+ // fail since we only mock workspace dir — causing it to return null
228
+ const result = resolveExplicitHubPath('project-x/hub-y');
229
+ expect('segments' in result).toBe(true);
230
+ if ('segments' in result) {
231
+ expect(result.segments.project).toBe('project-x');
232
+ expect(result.segments.hub).toBe('hub-y');
233
+ expect(result.segments.orgPrefix).toBeUndefined();
234
+ }
235
+ });
236
+ it('returns resolved hub for 2-part path when workspace has matching folder', () => {
237
+ const gitRoot = '/home/user/repo';
238
+ const workspaceDir = path.join(gitRoot, 'workspace');
239
+ const candidateFolder = path.join(workspaceDir, 'support', 'customer-hub');
240
+ const yamlPath = path.join(candidateFolder, 'wayai.yaml');
241
+ // execFileSync for git rev-parse
242
+ mockExecFileSync.mockReturnValue(gitRoot + '\n');
243
+ // existsSync: workspace dir, wayai.yaml
244
+ mockExistsSync.mockImplementation((p) => {
245
+ if (p === workspaceDir)
246
+ return true;
247
+ if (p === yamlPath)
248
+ return true;
249
+ return false;
250
+ });
251
+ // statSync: workspace dir is a directory, candidate hub folder is a directory
252
+ mockStatSync.mockImplementation((p) => {
253
+ if (p === workspaceDir || p === candidateFolder) {
254
+ return { isDirectory: () => true };
255
+ }
256
+ throw new Error(`ENOENT: ${String(p)}`);
257
+ });
258
+ // readFileSync: wayai.yaml content
259
+ mockReadFileSync.mockImplementation((p) => {
260
+ if (p === yamlPath) {
261
+ return `hub_id: "hub-resolved-id"
262
+ hub_environment: production
263
+ hub:
264
+ name: Customer Hub
265
+ `;
266
+ }
267
+ throw new Error(`ENOENT: ${String(p)}`);
268
+ });
269
+ const result = resolveExplicitHubPath('support/customer-hub');
270
+ expect('resolved' in result).toBe(true);
271
+ if ('resolved' in result) {
272
+ expect(result.resolved.hubId).toBe('hub-resolved-id');
273
+ expect(result.resolved.hubFolder).toBe(candidateFolder);
274
+ expect(result.resolved.hubEnvironment).toBe('production');
275
+ }
276
+ });
277
+ it('returns segments for 3-part path even when workspace exists but hub not found', () => {
278
+ const gitRoot = '/home/user/repo';
279
+ mockWorkspaceAt(gitRoot);
280
+ // For 3-part path, project segment is parts[1] and hub segment is parts[2]
281
+ // The folder lookup uses project="my-project" and hub="my-hub"
282
+ const result = resolveExplicitHubPath('acme-org/my-project/my-hub');
283
+ expect('segments' in result).toBe(true);
284
+ if ('segments' in result) {
285
+ expect(result.segments.orgPrefix).toBe('acme-org');
286
+ expect(result.segments.project).toBe('my-project');
287
+ expect(result.segments.hub).toBe('my-hub');
288
+ }
289
+ });
290
+ it('returns resolved hub for 3-part path when workspace has matching folder', () => {
291
+ const gitRoot = '/home/user/repo';
292
+ const workspaceDir = path.join(gitRoot, 'workspace');
293
+ // Note: for 3-part path, the folder lookup uses parts[1] (project) and parts[2] (hub)
294
+ const candidateFolder = path.join(workspaceDir, 'sales', 'lead-hub');
295
+ const yamlPath = path.join(candidateFolder, 'wayai.yaml');
296
+ mockExecFileSync.mockReturnValue(gitRoot + '\n');
297
+ mockExistsSync.mockImplementation((p) => {
298
+ if (p === workspaceDir)
299
+ return true;
300
+ if (p === yamlPath)
301
+ return true;
302
+ return false;
303
+ });
304
+ mockStatSync.mockImplementation((p) => {
305
+ if (p === workspaceDir || p === candidateFolder) {
306
+ return { isDirectory: () => true };
307
+ }
308
+ throw new Error(`ENOENT: ${String(p)}`);
309
+ });
310
+ mockReadFileSync.mockImplementation((p) => {
311
+ if (p === yamlPath) {
312
+ return `hub_id: "hub-lead-456"
313
+ hub_environment: preview
314
+ hub:
315
+ name: Lead Hub
316
+ `;
317
+ }
318
+ throw new Error(`ENOENT: ${String(p)}`);
319
+ });
320
+ const result = resolveExplicitHubPath('acme-org/sales/lead-hub');
321
+ expect('resolved' in result).toBe(true);
322
+ if ('resolved' in result) {
323
+ expect(result.resolved.hubId).toBe('hub-lead-456');
324
+ expect(result.resolved.hubFolder).toBe(candidateFolder);
325
+ expect(result.resolved.hubEnvironment).toBe('preview');
326
+ }
327
+ });
328
+ });
329
+ //# sourceMappingURL=workspace.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.test.js","sourceRoot":"","sources":["../../src/lib/workspace.test.ts"],"names":[],"mappings":"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"}
@@ -62,16 +62,20 @@ function buildYamlPayload(payload) {
62
62
  version: payload.version,
63
63
  hub_id: payload.hub_id,
64
64
  hub_environment: payload.hub_environment,
65
- hub: payload.hub,
66
65
  };
66
+ // Include preview_label for preview hubs (read-only metadata)
67
+ if (payload.preview_label) {
68
+ result.preview_label = payload.preview_label;
69
+ }
70
+ result.hub = payload.hub;
67
71
  if (payload.agents && payload.agents.length > 0) {
68
72
  result.agents = payload.agents.map((agent) => {
69
73
  const entry = { ...agent };
70
- // Replace inline instructions with file reference
71
- if (agent.instructions) {
72
- const slug = slugify(agent.name);
73
- entry.instructions = `agents/${slug}.md`;
74
- }
74
+ // Remove inline instructions convention-based path resolution (agents/<slug>.md)
75
+ // The .md file is still written by extractAgentFiles().
76
+ // Note: the writer is only called during `pull` (payload has inline text from server).
77
+ // Explicit .md path overrides in YAML are preserved across `push` (parser handles them).
78
+ delete entry.instructions;
75
79
  return entry;
76
80
  });
77
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-writer.js","sourceRoot":"","sources":["../../src/lib/yaml-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"yaml-writer.js","sourceRoot":"","sources":["../../src/lib/yaml-writer.ts"],"names":[],"mappings":"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"}