@elench/testkit 0.1.100 → 0.1.102

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 (38) hide show
  1. package/README.md +6 -3
  2. package/lib/cli/args.mjs +0 -19
  3. package/lib/cli/assistant/app.mjs +6 -0
  4. package/lib/cli/assistant/command-observer.mjs +75 -44
  5. package/lib/cli/assistant/command-results.mjs +29 -2
  6. package/lib/cli/assistant/context-pack.mjs +21 -1
  7. package/lib/cli/assistant/providers/claude.mjs +42 -7
  8. package/lib/cli/assistant/providers/codex.mjs +87 -9
  9. package/lib/cli/assistant/providers/events.mjs +71 -0
  10. package/lib/cli/assistant/providers/index.mjs +5 -4
  11. package/lib/cli/assistant/providers/shared.mjs +40 -21
  12. package/lib/cli/assistant/session.mjs +46 -8
  13. package/lib/cli/assistant/settings.mjs +29 -6
  14. package/lib/cli/assistant/state.mjs +181 -6
  15. package/lib/cli/assistant/transcript-text.mjs +35 -0
  16. package/lib/cli/assistant/view-model.mjs +11 -0
  17. package/lib/cli/command-flags.mjs +0 -3
  18. package/lib/cli/entrypoint.mjs +0 -2
  19. package/lib/cli/operations/run/operation.mjs +0 -3
  20. package/lib/runner/live-run.mjs +5 -1
  21. package/lib/runner/orchestrator.mjs +26 -26
  22. package/lib/runner/planning.mjs +0 -75
  23. package/lib/runner/provenance.mjs +20 -0
  24. package/lib/runner/reporting.mjs +14 -9
  25. package/lib/runner/run-finalization.mjs +5 -2
  26. package/lib/runner/run-guards.mjs +0 -1
  27. package/lib/runner/scheduler/estimates.mjs +61 -0
  28. package/lib/runner/scheduler/identity.mjs +31 -0
  29. package/lib/runner/scheduler/index.mjs +126 -0
  30. package/lib/runner/scheduler/observations.mjs +27 -0
  31. package/lib/runner/selection.mjs +1 -2
  32. package/lib/runner/worker-loop.mjs +3 -4
  33. package/lib/timing/index.mjs +33 -33
  34. package/node_modules/@elench/next-analysis/package.json +1 -1
  35. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  36. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  37. package/node_modules/@elench/ts-analysis/package.json +1 -1
  38. package/package.json +14 -8
@@ -1,6 +1,7 @@
1
1
  import { formatError } from "./formatting.mjs";
2
2
  import { runDalTask, runHttpK6Task } from "./default-runtime-runner.mjs";
3
3
  import { runPlaywrightTask } from "./playwright-runner.mjs";
4
+ import { buildTimingObservation } from "./scheduler/observations.mjs";
4
5
 
5
6
  const HTTP_K6_TYPES = new Set(["integration", "e2e", "scenario", "load"]);
6
7
 
@@ -72,10 +73,8 @@ export async function runWorker(
72
73
  const outcome = await runTask(lease.context, task, lifecycle, lease, reporter);
73
74
  recordTaskOutcome(trackers, outcome.task, outcome);
74
75
  reporter?.taskFinished?.(outcome.task, outcome);
75
- timingUpdates.push({
76
- key: outcome.task.timingKey,
77
- durationMs: outcome.durationMs,
78
- });
76
+ const timingObservation = buildTimingObservation(outcome.task, outcome);
77
+ if (timingObservation) timingUpdates.push(timingObservation);
79
78
  worker.taskCount += 1;
80
79
  await runtimeManager.release(lease);
81
80
  } catch (error) {
@@ -1,5 +1,3 @@
1
- import path from "path";
2
-
3
1
  export function createEmptyTimings() {
4
2
  return {
5
3
  version: 1,
@@ -8,9 +6,24 @@ export function createEmptyTimings() {
8
6
  }
9
7
 
10
8
  export function normalizeTimings(parsed) {
9
+ const files = {};
10
+ const parsedFiles = parsed?.files && typeof parsed.files === "object" ? parsed.files : {};
11
+ for (const [key, entry] of Object.entries(parsedFiles)) {
12
+ const durationMs = Math.max(0, Math.round(Number(entry?.durationMs || entry?.avgDurationMs || 0)));
13
+ files[key] = {
14
+ durationMs,
15
+ avgDurationMs: Math.max(0, Math.round(Number(entry?.avgDurationMs || durationMs || 0))),
16
+ lastDurationMs: Math.max(0, Math.round(Number(entry?.lastDurationMs || durationMs || 0))),
17
+ minDurationMs: Math.max(0, Math.round(Number(entry?.minDurationMs || durationMs || 0))),
18
+ maxDurationMs: Math.max(0, Math.round(Number(entry?.maxDurationMs || durationMs || 0))),
19
+ runs: Number(entry?.runs || 0),
20
+ lastStatus: entry?.lastStatus || null,
21
+ updatedAt: entry?.updatedAt || null,
22
+ };
23
+ }
11
24
  return {
12
25
  version: 1,
13
- files: parsed?.files && typeof parsed.files === "object" ? parsed.files : {},
26
+ files,
14
27
  };
15
28
  }
16
29
 
@@ -21,53 +34,40 @@ export function applyTimingUpdates(timings, updates, updatedAt = new Date().toIS
21
34
  };
22
35
 
23
36
  for (const update of updates) {
37
+ if (!update?.key) continue;
38
+ const updateDurationMs = Math.max(1, Math.round(Number(update.durationMs || 0)));
39
+ if (!Number.isFinite(updateDurationMs)) continue;
24
40
  const existing = next.files[update.key];
25
41
  if (!existing) {
26
42
  next.files[update.key] = {
27
- durationMs: Math.max(1, Math.round(update.durationMs)),
43
+ durationMs: updateDurationMs,
44
+ avgDurationMs: updateDurationMs,
45
+ lastDurationMs: updateDurationMs,
46
+ minDurationMs: updateDurationMs,
47
+ maxDurationMs: updateDurationMs,
28
48
  runs: 1,
49
+ lastStatus: update.status || null,
29
50
  updatedAt,
30
51
  };
31
52
  continue;
32
53
  }
33
54
 
34
55
  const runs = Number(existing.runs || 0) + 1;
35
- const durationMs = Math.max(
56
+ const avgDurationMs = Math.max(
36
57
  1,
37
- Math.round(((existing.durationMs || update.durationMs) * (runs - 1) + update.durationMs) / runs)
58
+ Math.round(((existing.avgDurationMs || existing.durationMs || updateDurationMs) * (runs - 1) + updateDurationMs) / runs)
38
59
  );
39
60
  next.files[update.key] = {
40
- durationMs,
61
+ durationMs: avgDurationMs,
62
+ avgDurationMs,
63
+ lastDurationMs: updateDurationMs,
64
+ minDurationMs: Math.min(Number(existing.minDurationMs || updateDurationMs), updateDurationMs),
65
+ maxDurationMs: Math.max(Number(existing.maxDurationMs || updateDurationMs), updateDurationMs),
41
66
  runs,
67
+ lastStatus: update.status || existing.lastStatus || null,
42
68
  updatedAt,
43
69
  };
44
70
  }
45
71
 
46
72
  return next;
47
73
  }
48
-
49
- export function estimateTaskDuration(timings, timingKey, suite) {
50
- const cached = timings.files[timingKey];
51
- if (cached?.durationMs) return cached.durationMs;
52
-
53
- const base =
54
- suite.framework === "playwright"
55
- ? 20_000
56
- : suite.type === "dal"
57
- ? 4_000
58
- : 8_000;
59
- return Math.max(1_000, Math.round((base * suite.weight) / Math.max(1, suite.files.length)));
60
- }
61
-
62
- export function buildTimingKey(serviceName, suite, file) {
63
- return [
64
- serviceName,
65
- suite.framework,
66
- suite.type,
67
- normalizePathSeparators(file),
68
- ].join("|");
69
- }
70
-
71
- function normalizePathSeparators(filePath) {
72
- return filePath.split(path.sep).join("/");
73
- }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/next-analysis",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "SWC-backed Next.js source analysis primitives for Erench tools",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/testkit-bridge",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "Browser bridge helpers for testkit",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "typecheck": "tsc -p tsconfig.json --noEmit"
23
23
  },
24
24
  "dependencies": {
25
- "@elench/testkit-protocol": "0.1.100"
25
+ "@elench/testkit-protocol": "0.1.102"
26
26
  },
27
27
  "private": false
28
28
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/testkit-protocol",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "Shared browser protocol for testkit bridge and extension consumers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/ts-analysis",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "TypeScript compiler-backed source analysis primitives for Erench tools",
5
5
  "type": "module",
6
6
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/testkit",
3
- "version": "0.1.100",
3
+ "version": "0.1.102",
4
4
  "description": "Assistant-first CLI for running, inspecting, and debugging local testkit suites",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -58,11 +58,12 @@
58
58
  "scripts": {
59
59
  "build:packages": "npm --workspace packages/testkit-protocol run build && npm --workspace packages/ts-analysis run build && npm --workspace packages/next-analysis run build && npm --workspace packages/testkit-bridge run build",
60
60
  "typecheck:packages": "npm --workspace packages/testkit-protocol run typecheck && npm --workspace packages/ts-analysis run typecheck && npm --workspace packages/next-analysis run typecheck && npm --workspace packages/testkit-bridge run typecheck && npm --workspace packages/testkit-extension run compile",
61
- "test": "npm run build:packages && vitest run && node scripts/live-sandbox/harness.mjs",
61
+ "test": "npm run build:packages && vitest run && npm run test:live",
62
62
  "test:audit": "node scripts/test-boundary-audit.mjs",
63
+ "test:live": "node scripts/live-sandbox/harness.mjs",
63
64
  "test:unit": "npm run build:packages && npm run test:audit && vitest run --config vitest.unit.config.mjs",
64
65
  "test:integration": "npm run build:packages && vitest run test/integration",
65
- "test:system": "npm run build:packages && vitest run test/system --passWithNoTests"
66
+ "test:system": "npm run build:packages && vitest run test/system"
66
67
  },
67
68
  "files": [
68
69
  "bin/",
@@ -89,10 +90,10 @@
89
90
  },
90
91
  "dependencies": {
91
92
  "@babel/code-frame": "^7.29.0",
92
- "@elench/next-analysis": "0.1.100",
93
- "@elench/testkit-bridge": "0.1.100",
94
- "@elench/testkit-protocol": "0.1.100",
95
- "@elench/ts-analysis": "0.1.100",
93
+ "@elench/next-analysis": "0.1.102",
94
+ "@elench/testkit-bridge": "0.1.102",
95
+ "@elench/testkit-protocol": "0.1.102",
96
+ "@elench/ts-analysis": "0.1.102",
96
97
  "@oclif/core": "^4.10.6",
97
98
  "esbuild": "^0.25.11",
98
99
  "execa": "^9.5.0",
@@ -109,6 +110,11 @@
109
110
  "wrap-ansi": "^10.0.0"
110
111
  },
111
112
  "engines": {
112
- "node": ">=18"
113
+ "node": ">=24.14.1",
114
+ "npm": ">=11.11.0"
115
+ },
116
+ "volta": {
117
+ "node": "24.14.1",
118
+ "npm": "11.11.0"
113
119
  }
114
120
  }