@zibby/core 0.4.5 → 0.5.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 (81) hide show
  1. package/dist/index.js +147 -150
  2. package/dist/package.json +1 -8
  3. package/dist/register-built-in-strategies.js +32 -32
  4. package/dist/strategies/claude-strategy.js +2 -2
  5. package/dist/strategies/index.js +45 -45
  6. package/dist/utils/run-index-post-cli.js +1 -4
  7. package/package.json +1 -8
  8. package/dist/templates/browser-test-automation/README.md +0 -136
  9. package/dist/templates/browser-test-automation/chat.mjs +0 -36
  10. package/dist/templates/browser-test-automation/graph.mjs +0 -80
  11. package/dist/templates/browser-test-automation/nodes/cache-replay.mjs +0 -213
  12. package/dist/templates/browser-test-automation/nodes/execute-live.mjs +0 -254
  13. package/dist/templates/browser-test-automation/nodes/generate-script.mjs +0 -108
  14. package/dist/templates/browser-test-automation/nodes/index.mjs +0 -4
  15. package/dist/templates/browser-test-automation/nodes/preflight.mjs +0 -94
  16. package/dist/templates/browser-test-automation/nodes/utils.mjs +0 -297
  17. package/dist/templates/browser-test-automation/pipeline-ids.js +0 -12
  18. package/dist/templates/browser-test-automation/result-handler.mjs +0 -327
  19. package/dist/templates/browser-test-automation/run-index.mjs +0 -420
  20. package/dist/templates/browser-test-automation/run_test.json +0 -358
  21. package/dist/templates/browser-test-automation/state.js +0 -61
  22. package/dist/templates/code-analysis/README.md +0 -60
  23. package/dist/templates/code-analysis/graph.js +0 -72
  24. package/dist/templates/code-analysis/graph.mjs +0 -33
  25. package/dist/templates/code-analysis/index.js +0 -18
  26. package/dist/templates/code-analysis/nodes/analyze-ticket-node.js +0 -204
  27. package/dist/templates/code-analysis/nodes/create-pr-node.js +0 -175
  28. package/dist/templates/code-analysis/nodes/finalize-node.js +0 -118
  29. package/dist/templates/code-analysis/nodes/generate-code-node.js +0 -425
  30. package/dist/templates/code-analysis/nodes/generate-test-cases-node.js +0 -376
  31. package/dist/templates/code-analysis/nodes/services/prMetaService.js +0 -86
  32. package/dist/templates/code-analysis/nodes/setup-node.js +0 -142
  33. package/dist/templates/code-analysis/prompts/analyze-ticket.md +0 -181
  34. package/dist/templates/code-analysis/prompts/generate-code.md +0 -33
  35. package/dist/templates/code-analysis/prompts/generate-test-cases.md +0 -110
  36. package/dist/templates/code-analysis/state.js +0 -48
  37. package/dist/templates/generate-test-cases/README.md +0 -72
  38. package/dist/templates/generate-test-cases/graph.mjs +0 -46
  39. package/dist/templates/generate-test-cases/nodes/generate-test-cases-node.js +0 -381
  40. package/dist/templates/generate-test-cases/nodes/setup-node.js +0 -142
  41. package/dist/templates/generate-test-cases/state.js +0 -54
  42. package/dist/templates/global-setup.js +0 -56
  43. package/dist/templates/index.js +0 -147
  44. package/dist/templates/register-nodes.js +0 -24
  45. package/templates/browser-test-automation/README.md +0 -136
  46. package/templates/browser-test-automation/chat.mjs +0 -36
  47. package/templates/browser-test-automation/graph.mjs +0 -80
  48. package/templates/browser-test-automation/nodes/cache-replay.mjs +0 -213
  49. package/templates/browser-test-automation/nodes/execute-live.mjs +0 -254
  50. package/templates/browser-test-automation/nodes/generate-script.mjs +0 -108
  51. package/templates/browser-test-automation/nodes/index.mjs +0 -4
  52. package/templates/browser-test-automation/nodes/preflight.mjs +0 -94
  53. package/templates/browser-test-automation/nodes/utils.mjs +0 -297
  54. package/templates/browser-test-automation/pipeline-ids.js +0 -12
  55. package/templates/browser-test-automation/result-handler.mjs +0 -327
  56. package/templates/browser-test-automation/run-index.mjs +0 -420
  57. package/templates/browser-test-automation/run_test.json +0 -358
  58. package/templates/browser-test-automation/state.js +0 -61
  59. package/templates/code-analysis/README.md +0 -60
  60. package/templates/code-analysis/graph.js +0 -72
  61. package/templates/code-analysis/graph.mjs +0 -33
  62. package/templates/code-analysis/index.js +0 -18
  63. package/templates/code-analysis/nodes/analyze-ticket-node.js +0 -204
  64. package/templates/code-analysis/nodes/create-pr-node.js +0 -175
  65. package/templates/code-analysis/nodes/finalize-node.js +0 -118
  66. package/templates/code-analysis/nodes/generate-code-node.js +0 -425
  67. package/templates/code-analysis/nodes/generate-test-cases-node.js +0 -376
  68. package/templates/code-analysis/nodes/services/prMetaService.js +0 -86
  69. package/templates/code-analysis/nodes/setup-node.js +0 -142
  70. package/templates/code-analysis/prompts/analyze-ticket.md +0 -181
  71. package/templates/code-analysis/prompts/generate-code.md +0 -33
  72. package/templates/code-analysis/prompts/generate-test-cases.md +0 -110
  73. package/templates/code-analysis/state.js +0 -48
  74. package/templates/generate-test-cases/README.md +0 -72
  75. package/templates/generate-test-cases/graph.mjs +0 -46
  76. package/templates/generate-test-cases/nodes/generate-test-cases-node.js +0 -381
  77. package/templates/generate-test-cases/nodes/setup-node.js +0 -142
  78. package/templates/generate-test-cases/state.js +0 -54
  79. package/templates/global-setup.js +0 -56
  80. package/templates/index.js +0 -147
  81. package/templates/register-nodes.js +0 -24
@@ -1,420 +0,0 @@
1
- /**
2
- * Browser test automation — run-index.jsonl rows (execute_live / generate_script layout).
3
- * Used by CLI runTest; generic JSONL I/O is in @zibby/core/utils/run-registry.js.
4
- */
5
-
6
- import { existsSync, readdirSync, statSync } from 'fs';
7
- import { join, relative, sep, resolve as pathResolve } from 'path';
8
- import {
9
- appendRunIndexRecord,
10
- readRunIndexRecordsFromFile,
11
- resolveRunIndexPath,
12
- } from '../../src/utils/run-registry.js';
13
- import { mergeSessionRunState, readSessionRunState } from '../../src/utils/run-state-session.js';
14
- import { partitionRunIndexBySession, runIndexSessionEntryIsLive } from '../../src/utils/run-index-merge.js';
15
- import { DEFAULT_OUTPUT_BASE, SESSIONS_DIR } from '@zibby/agent-workflow';
16
- import { BROWSER_TEST_PIPELINE_NODE_IDS } from './pipeline-ids.js';
17
-
18
- export { BROWSER_TEST_PIPELINE_NODE_IDS };
19
-
20
- /** Stable id for Studio + run-index: Studio env, else session folder id (CLI/chat). */
21
- function runIndexCorrelationId(sessionId) {
22
- const env = process.env.ZIBBY_STUDIO_TEST_CASE_ID;
23
- if (env != null && String(env).trim() !== '') return String(env).trim();
24
- return sessionId != null ? String(sessionId) : '';
25
- }
26
-
27
- const SCRIPT_CANDIDATES = [
28
- join('generate_script', 'generated-test.spec.js'),
29
- join('generate_script', 'generated-test.spec.ts'),
30
- join('generate_script', 'playwright.spec.ts'),
31
- join('generate_script', 'test.spec.ts'),
32
- ];
33
-
34
- function firstExistingVideo(sessionAbs) {
35
- const dirs = [
36
- join(sessionAbs, 'execute_live', 'videos'),
37
- join(sessionAbs, 'execute_live'),
38
- sessionAbs,
39
- ];
40
- for (const d of dirs) {
41
- if (!existsSync(d)) continue;
42
- let names;
43
- try {
44
- names = readdirSync(d);
45
- } catch {
46
- continue;
47
- }
48
- const webm = names.find((f) => f.endsWith('.webm'));
49
- if (webm) return join(d, webm);
50
- }
51
- return null;
52
- }
53
-
54
- function firstExistingEvents(sessionAbs) {
55
- const c = [join(sessionAbs, 'execute_live', 'events.json'), join(sessionAbs, 'events.json')];
56
- for (const p of c) {
57
- if (existsSync(p)) return p;
58
- }
59
- return null;
60
- }
61
-
62
- function firstExistingScript(sessionAbs) {
63
- for (const rel of SCRIPT_CANDIDATES) {
64
- const p = join(sessionAbs, rel);
65
- if (existsSync(p)) return p;
66
- }
67
- return null;
68
- }
69
-
70
- /**
71
- * Discover absolute artifact paths for a browser-test session directory.
72
- * @param {string} sessionPathAbs
73
- */
74
- export function discoverBrowserTestSessionArtifacts(sessionPathAbs) {
75
- if (!sessionPathAbs || !existsSync(sessionPathAbs)) {
76
- return { videoPathAbs: null, eventsPathAbs: null, scriptPathAbs: null };
77
- }
78
- return {
79
- videoPathAbs: firstExistingVideo(sessionPathAbs),
80
- eventsPathAbs: firstExistingEvents(sessionPathAbs),
81
- scriptPathAbs: firstExistingScript(sessionPathAbs),
82
- };
83
- }
84
-
85
- /**
86
- * @param {object} opts
87
- * @param {string} opts.cwd
88
- * @param {object} opts.result - return value from agent.run / runSingleNode
89
- * @param {boolean} opts.success
90
- * @param {string} [opts.outputBase]
91
- * @param {string} [opts.specPath]
92
- * @param {string} [opts.errorMessage]
93
- * @param {string} [opts.status] — override default completed/failed (e.g. `interrupted`)
94
- */
95
- export function buildBrowserTestRunIndexRecord(opts) {
96
- const cwd = opts.cwd || process.cwd();
97
- const outputBase = opts.outputBase || DEFAULT_OUTPUT_BASE;
98
- const result = opts.result || {};
99
- const state = result.state || {};
100
- const sessionPathAbs = state.sessionPath;
101
- if (!sessionPathAbs || typeof sessionPathAbs !== 'string') {
102
- return null;
103
- }
104
-
105
- const sessionId = sessionPathAbs.split(/[/\\]/).filter(Boolean).pop();
106
- if (!sessionId) return null;
107
-
108
- const { videoPathAbs, eventsPathAbs, scriptPathAbs } =
109
- discoverBrowserTestSessionArtifacts(sessionPathAbs);
110
-
111
- const toRel = (abs) => {
112
- if (!abs) return null;
113
- try {
114
- return relative(cwd, abs).split(sep).join('/');
115
- } catch {
116
- return null;
117
- }
118
- };
119
-
120
- let specRel = null;
121
- if (opts.specPath) {
122
- try {
123
- const absSpec = pathResolve(cwd, opts.specPath);
124
- specRel = relative(cwd, absSpec).split(sep).join('/');
125
- } catch {
126
- specRel = String(opts.specPath).split(sep).join('/');
127
- }
128
- }
129
-
130
- return {
131
- v: 1,
132
- recordKind: 'summary',
133
- ts: Date.now(),
134
- sessionId,
135
- status: opts.status ?? (opts.success ? 'completed' : 'failed'),
136
- cwd,
137
- outputBase,
138
- sessionPathAbs,
139
- sessionDirRel: toRel(sessionPathAbs),
140
- videoPathAbs: videoPathAbs || null,
141
- eventsPathAbs: eventsPathAbs || null,
142
- scriptPathAbs: scriptPathAbs || null,
143
- videoRel: toRel(videoPathAbs),
144
- eventsRel: toRel(eventsPathAbs),
145
- scriptRel: toRel(scriptPathAbs),
146
- specRel,
147
- source: process.env.ZIBBY_RUN_SOURCE || 'cli',
148
- studioTestCaseId: runIndexCorrelationId(sessionId) || null,
149
- errorMessage: opts.errorMessage || null,
150
- };
151
- }
152
-
153
- export function tryAppendBrowserTestRunIndex({
154
- cwd,
155
- config,
156
- result,
157
- success,
158
- specPath,
159
- errorMessage,
160
- }) {
161
- try {
162
- const record = buildBrowserTestRunIndexRecord({
163
- cwd: cwd || process.cwd(),
164
- result,
165
- success,
166
- outputBase: config?.paths?.output || DEFAULT_OUTPUT_BASE,
167
- specPath,
168
- errorMessage,
169
- });
170
- if (record) {
171
- appendRunIndexRecord(record);
172
- if (record.sessionPathAbs) {
173
- mergeSessionRunState(record.sessionPathAbs, {
174
- sessionId: record.sessionId,
175
- studioTestCaseId: record.studioTestCaseId || record.sessionId,
176
- status: record.status,
177
- activeNode: null,
178
- activeStageIndex: null,
179
- errorMessage: record.errorMessage || null,
180
- runSource: record.source || 'cli',
181
- cwd: record.cwd,
182
- outputBase: record.outputBase,
183
- sessionPathAbs: record.sessionPathAbs,
184
- });
185
- }
186
- }
187
- } catch (e) {
188
- console.warn(`[zibby browser-test run-index] ${e.message}`);
189
- }
190
- }
191
-
192
- /**
193
- * Append one JSONL row when a pipeline node starts (live Mission Control).
194
- * @param {object} payload
195
- * @param {string} payload.currentNode — graph node id
196
- * @param {string} payload.sessionPath — absolute session dir
197
- * @param {string} [payload.sessionId]
198
- * @param {string} [payload.cwd]
199
- * @param {string} [payload.outputBase]
200
- */
201
- /**
202
- * Single absolute session directory for pipeline progress + zibby-run-state.json.
203
- * Studio spawns the CLI with ZIBBY_SESSION_PATH; cwd may still be wrong (home, app bundle, etc.).
204
- * Never merge under join(cwd, …/sessions/id) when studio env points elsewhere — that caused duplicate dirs.
205
- */
206
- export function resolveBrowserTestPipelineSessionPathAbs({
207
- sessionPath,
208
- sessionId,
209
- cwd,
210
- outputBase = DEFAULT_OUTPUT_BASE,
211
- } = {}) {
212
- const cwd0 = cwd || process.cwd();
213
- const ob = outputBase || DEFAULT_OUTPUT_BASE;
214
- const sid =
215
- sessionId != null && String(sessionId).trim() !== ''
216
- ? String(sessionId).trim()
217
- : null;
218
-
219
- const pinned =
220
- process.env.ZIBBY_PIN_SESSION_PATH === '1' ||
221
- process.env.ZIBBY_PIN_SESSION_PATH === 'true';
222
- const envSession = process.env.ZIBBY_SESSION_PATH && String(process.env.ZIBBY_SESSION_PATH).trim();
223
- if (pinned && envSession) {
224
- return pathResolve(envSession);
225
- }
226
-
227
- const trimmed = sessionPath && String(sessionPath).trim();
228
- if (trimmed) {
229
- return pathResolve(trimmed);
230
- }
231
-
232
- const sessionsRoot = process.env.ZIBBY_SESSIONS_ROOT && String(process.env.ZIBBY_SESSIONS_ROOT).trim();
233
- if (sessionsRoot && sid) {
234
- return pathResolve(join(sessionsRoot, sid));
235
- }
236
-
237
- if (process.env.ZIBBY_SESSION_PATH && String(process.env.ZIBBY_SESSION_PATH).trim()) {
238
- return pathResolve(String(process.env.ZIBBY_SESSION_PATH).trim());
239
- }
240
-
241
- return pathResolve(join(cwd0, ob, SESSIONS_DIR, sid || 'invalid'));
242
- }
243
-
244
- export function tryAppendBrowserTestPipelineProgress(payload) {
245
- try {
246
- const currentNode = payload?.currentNode;
247
- if (!currentNode || !BROWSER_TEST_PIPELINE_NODE_IDS.includes(currentNode)) return;
248
-
249
- const sessionPath = payload.sessionPath;
250
- const sessionId =
251
- payload.sessionId ||
252
- (sessionPath && String(sessionPath).split(/[/\\]/).filter(Boolean).pop()) ||
253
- null;
254
- if (!sessionId) return;
255
-
256
- const cwd = payload.cwd || process.cwd();
257
- const outputBase = payload.outputBase || DEFAULT_OUTPUT_BASE;
258
- const activeStageIndex = BROWSER_TEST_PIPELINE_NODE_IDS.indexOf(currentNode);
259
- const specPathRaw = payload?.specPath != null ? String(payload.specPath).trim() : '';
260
- const taskDescription =
261
- payload?.taskDescription != null ? String(payload.taskDescription) : '';
262
- let specRel = null;
263
- if (specPathRaw) {
264
- try {
265
- const absSpec = pathResolve(cwd, specPathRaw);
266
- specRel = relative(cwd, absSpec).split(sep).join('/');
267
- } catch {
268
- specRel = specPathRaw.split(sep).join('/');
269
- }
270
- }
271
-
272
- const sessionPathAbs = resolveBrowserTestPipelineSessionPathAbs({
273
- sessionPath,
274
- sessionId,
275
- cwd,
276
- outputBase,
277
- });
278
-
279
- appendRunIndexRecord({
280
- v: 1,
281
- recordKind: 'progress',
282
- ts: Date.now(),
283
- sessionId,
284
- cwd,
285
- outputBase,
286
- sessionPathAbs,
287
- activeNode: currentNode,
288
- activeStageIndex,
289
- specRel,
290
- taskDescription: taskDescription || null,
291
- studioTestCaseId: runIndexCorrelationId(sessionId) || null,
292
- source: process.env.ZIBBY_RUN_SOURCE || 'cli',
293
- });
294
-
295
- mergeSessionRunState(sessionPathAbs, {
296
- sessionId,
297
- studioTestCaseId: runIndexCorrelationId(sessionId) || sessionId,
298
- status: 'running',
299
- activeNode: currentNode,
300
- activeStageIndex,
301
- sessionPathAbs,
302
- cwd,
303
- outputBase,
304
- specPath: specRel || null,
305
- task: taskDescription || null,
306
- taskDescription: taskDescription || null,
307
- runSource: process.env.ZIBBY_RUN_SOURCE || 'cli',
308
- pid: typeof process.pid === 'number' ? process.pid : null,
309
- });
310
- } catch (e) {
311
- console.warn(`[zibby browser-test run-index progress] ${e.message}`);
312
- }
313
- }
314
-
315
- /** Factory for graph.run `initialState.onPipelineProgress`. */
316
- export function createBrowserTestPipelineProgressAppender({ cwd, config } = {}) {
317
- const cwd0 = cwd || process.cwd();
318
- const ob0 = config?.paths?.output || DEFAULT_OUTPUT_BASE;
319
- return (payload) => {
320
- tryAppendBrowserTestPipelineProgress({
321
- cwd: payload?.cwd || cwd0,
322
- outputBase: payload?.outputBase || ob0,
323
- sessionPath: payload?.sessionPath,
324
- sessionId: payload?.sessionId,
325
- currentNode: payload?.currentNode,
326
- specPath: payload?.specPath,
327
- taskDescription: payload?.taskDescription,
328
- });
329
- };
330
- }
331
-
332
- /**
333
- * Append a terminal `summary` row for every session that still looks “live” in run-index (progress newer than summary).
334
- * Call from SIGINT/SIGTERM so Mission Control clears after Ctrl+C in the terminal.
335
- * @param {object} [opts]
336
- * @param {string} [opts.cwd]
337
- * @param {object} [opts.config] — uses `config.paths.output`
338
- */
339
- export function tryAppendBrowserTestInterruptedRunIndex(opts = {}) {
340
- try {
341
- const cwd0 = opts.cwd || process.cwd();
342
- const outputBase = opts.config?.paths?.output || opts.outputBase || DEFAULT_OUTPUT_BASE;
343
- const indexPath = resolveRunIndexPath(cwd0, outputBase);
344
- const records = readRunIndexRecordsFromFile(indexPath);
345
- const partitioned = partitionRunIndexBySession(records);
346
- const handled = new Set();
347
-
348
- const errMsg =
349
- opts.errorMessage ||
350
- 'Run stopped (SIGINT/SIGTERM) before a normal summary was written.';
351
-
352
- const flushInterrupted = (sessionId, sessionPathAbs) => {
353
- if (!sessionId || !sessionPathAbs) return;
354
- if (handled.has(sessionId)) return;
355
- handled.add(sessionId);
356
- const record = buildBrowserTestRunIndexRecord({
357
- cwd: cwd0,
358
- outputBase,
359
- result: { state: { sessionPath: sessionPathAbs } },
360
- success: false,
361
- specPath: null,
362
- status: 'interrupted',
363
- errorMessage: errMsg,
364
- });
365
- if (record) {
366
- appendRunIndexRecord(record);
367
- mergeSessionRunState(sessionPathAbs, {
368
- sessionId,
369
- studioTestCaseId: record.studioTestCaseId || sessionId,
370
- status: 'interrupted',
371
- activeNode: null,
372
- activeStageIndex: null,
373
- errorMessage: record.errorMessage || null,
374
- runSource: record.source || 'cli',
375
- cwd: cwd0,
376
- outputBase,
377
- sessionPathAbs,
378
- });
379
- }
380
- };
381
-
382
- // 1) JSONL “live” sessions (progress newer than summary)
383
- for (const [folderSessionId, entry] of partitioned) {
384
- if (!runIndexSessionEntryIsLive(entry)) continue;
385
- const prog = entry.progress;
386
- if (!prog) continue;
387
- const sessionId = String(folderSessionId);
388
- const sessionPathAbs =
389
- (prog.sessionPathAbs && String(prog.sessionPathAbs)) ||
390
- join(cwd0, outputBase, SESSIONS_DIR, sessionId);
391
- flushInterrupted(sessionId, sessionPathAbs);
392
- }
393
-
394
- // 2) Disk-only live: Studio (or early CLI) wrote zibby-run-state.json as running before any
395
- // run-index progress line — JSONL partition omits them, so Ctrl+C must clear by scanning sessions/.
396
- const sessionsRoot = join(cwd0, outputBase, SESSIONS_DIR);
397
- if (!existsSync(sessionsRoot)) return;
398
- let names;
399
- try {
400
- names = readdirSync(sessionsRoot);
401
- } catch {
402
- return;
403
- }
404
- for (const name of names) {
405
- const sessionPathAbs = join(sessionsRoot, name);
406
- let st;
407
- try {
408
- st = statSync(sessionPathAbs);
409
- } catch {
410
- continue;
411
- }
412
- if (!st.isDirectory()) continue;
413
- const doc = readSessionRunState(sessionPathAbs);
414
- if (!doc || doc.status !== 'running') continue;
415
- flushInterrupted(String(name), sessionPathAbs);
416
- }
417
- } catch (e) {
418
- console.warn(`[zibby browser-test run-index interrupt] ${e.message}`);
419
- }
420
- }