pi-harness-runtime 1.1.49 → 1.1.71-3

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 (203) hide show
  1. package/CHANGELOG.md +30 -9
  2. package/README.md +119 -0
  3. package/harness/langchain/agents.d.ts +143 -0
  4. package/harness/langchain/agents.test.d.ts +2 -0
  5. package/harness/langchain/agents.test.ts +0 -1
  6. package/harness/langchain/agents.ts +196 -13
  7. package/harness/langchain/checkpointer.d.ts +48 -0
  8. package/harness/langchain/checkpointer.test.d.ts +8 -0
  9. package/harness/langchain/cron-cli.d.ts +12 -0
  10. package/harness/langchain/cron-cli.ts +169 -0
  11. package/harness/langchain/daemon.d.ts +161 -0
  12. package/harness/langchain/daemon.test.d.ts +11 -0
  13. package/harness/langchain/daemon.test.ts +62 -5
  14. package/harness/langchain/daemon.ts +231 -12
  15. package/harness/langchain/file-tools.d.ts +97 -0
  16. package/harness/langchain/file-tools.ts +29 -11
  17. package/harness/langchain/graph.d.ts +706 -0
  18. package/harness/langchain/graph.ts +184 -26
  19. package/harness/langchain/model-router.d.ts +63 -0
  20. package/harness/langchain/model-router.test.d.ts +2 -0
  21. package/harness/langchain/model-router.test.ts +191 -0
  22. package/harness/langchain/model-router.ts +188 -0
  23. package/harness/langchain/models.d.ts +72 -0
  24. package/harness/langchain/models.ts +111 -49
  25. package/harness/langchain/ping-pong-middleware.d.ts +28 -0
  26. package/harness/langchain/ping-pong-middleware.test.d.ts +2 -0
  27. package/harness/langchain/ping-pong-middleware.test.ts +69 -0
  28. package/harness/langchain/ping-pong-middleware.ts +204 -0
  29. package/harness/langchain/run.d.ts +15 -0
  30. package/harness/langchain/run.ts +15 -3
  31. package/harness/langchain/scoreboard.test.d.ts +13 -0
  32. package/harness/langchain/scoreboard.test.ts +28 -5
  33. package/harness/langchain/status-line.d.ts +91 -0
  34. package/harness/langchain/status-line.test.d.ts +8 -0
  35. package/harness/langchain/surge.d.ts +103 -0
  36. package/harness/langchain/surge.test.d.ts +10 -0
  37. package/harness/langchain/surge.test.ts +179 -0
  38. package/harness/langchain/surge.ts +188 -19
  39. package/harness/langchain/widget.d.ts +105 -0
  40. package/harness/langchain/widget.test.d.ts +8 -0
  41. package/harness/ssh-detach-interceptor.test.ts +263 -0
  42. package/harness/ssh-detach-interceptor.ts +438 -0
  43. package/index.ts +212 -47
  44. package/package.json +4 -2
  45. package/packages/a2a-adapter/package.json +1 -1
  46. package/packages/architecture-generator/package.json +1 -1
  47. package/packages/auth/package.json +1 -1
  48. package/packages/autonomous-refactor/package.json +1 -1
  49. package/packages/autonomous-runtime/package.json +1 -1
  50. package/packages/cache-strategy/package.json +1 -1
  51. package/packages/capability-registry/package.json +1 -1
  52. package/packages/checkpoint/package.json +1 -1
  53. package/packages/cli-plugin-sdk/package.json +1 -1
  54. package/packages/clipboard/package.json +1 -1
  55. package/packages/clipboard-plugin/package.json +1 -1
  56. package/packages/code-generation/package.json +1 -1
  57. package/packages/code-review/package.json +1 -1
  58. package/packages/codex-adapter/package.json +1 -1
  59. package/packages/config-capture/package.json +1 -1
  60. package/packages/context-compiler/package.json +1 -1
  61. package/packages/context-discovery/package.json +1 -1
  62. package/packages/context-manager/package.json +1 -1
  63. package/packages/cookie-sanitizer/package.json +1 -1
  64. package/packages/cost-optimizer/package.json +1 -1
  65. package/packages/dependency-analyzer/package.json +1 -1
  66. package/packages/django-plugin/package.json +1 -1
  67. package/packages/doc-generator/package.json +1 -1
  68. package/packages/evaluation-engine/package.json +1 -1
  69. package/packages/evaluation-runner/package.json +1 -1
  70. package/packages/event-bus/package.json +1 -1
  71. package/packages/event-store/package.json +1 -1
  72. package/packages/experience-replay/package.json +1 -1
  73. package/packages/feedback-collector/package.json +1 -1
  74. package/packages/file-copy-helper/package.json +1 -1
  75. package/packages/framework-detector/package.json +1 -1
  76. package/packages/framework-plugin-sdk/package.json +1 -1
  77. package/packages/frappe-plugin/package.json +1 -1
  78. package/packages/generic-web-plugin/package.json +1 -1
  79. package/packages/health-monitor/package.json +1 -1
  80. package/packages/intent-analyzer/dist/src/index.d.ts +2 -0
  81. package/packages/intent-analyzer/dist/src/index.d.ts.map +1 -1
  82. package/packages/intent-analyzer/dist/src/index.js +1 -0
  83. package/packages/intent-analyzer/dist/src/index.js.map +1 -1
  84. package/packages/intent-analyzer/dist/src/ping-pong.d.ts +56 -0
  85. package/packages/intent-analyzer/dist/src/ping-pong.d.ts.map +1 -0
  86. package/packages/intent-analyzer/dist/src/ping-pong.js +286 -0
  87. package/packages/intent-analyzer/dist/src/ping-pong.js.map +1 -0
  88. package/packages/intent-analyzer/package.json +1 -1
  89. package/packages/intent-analyzer/src/index.ts +13 -0
  90. package/packages/intent-analyzer/src/ping-pong.ts +387 -0
  91. package/packages/intent-analyzer/test/ping-pong.test.ts +96 -0
  92. package/packages/jev-judge/README.md +234 -0
  93. package/packages/jev-judge/dist/decision-engine.d.ts +100 -0
  94. package/packages/jev-judge/dist/decision-engine.d.ts.map +1 -0
  95. package/packages/jev-judge/dist/decision-engine.js +151 -0
  96. package/packages/jev-judge/dist/decision-engine.js.map +1 -0
  97. package/packages/jev-judge/dist/e2e-judge.d.ts +61 -0
  98. package/packages/jev-judge/dist/e2e-judge.d.ts.map +1 -0
  99. package/packages/jev-judge/dist/e2e-judge.js +268 -0
  100. package/packages/jev-judge/dist/e2e-judge.js.map +1 -0
  101. package/packages/jev-judge/dist/flaky-detector.d.ts +34 -0
  102. package/packages/jev-judge/dist/flaky-detector.d.ts.map +1 -0
  103. package/packages/jev-judge/dist/flaky-detector.js +154 -0
  104. package/packages/jev-judge/dist/flaky-detector.js.map +1 -0
  105. package/packages/jev-judge/dist/index.d.ts +77 -0
  106. package/packages/jev-judge/dist/index.d.ts.map +1 -0
  107. package/packages/jev-judge/dist/index.js +271 -0
  108. package/packages/jev-judge/dist/index.js.map +1 -0
  109. package/packages/jev-judge/dist/types.d.ts +97 -0
  110. package/packages/jev-judge/dist/types.d.ts.map +1 -0
  111. package/packages/jev-judge/dist/types.js +8 -0
  112. package/packages/jev-judge/dist/types.js.map +1 -0
  113. package/packages/jev-judge/package.json +46 -0
  114. package/packages/jev-judge/src/decision-engine.ts +231 -0
  115. package/packages/jev-judge/src/e2e-judge.ts +364 -0
  116. package/packages/jev-judge/src/flaky-detector.ts +190 -0
  117. package/packages/jev-judge/src/index.ts +345 -0
  118. package/packages/jev-judge/src/types.ts +131 -0
  119. package/packages/knowledge-graph/package.json +1 -1
  120. package/packages/knowledge-retrieval/package.json +1 -1
  121. package/packages/laravel-plugin/package.json +1 -1
  122. package/packages/learning-engine/package.json +1 -1
  123. package/packages/mcp-adapter/package.json +1 -1
  124. package/packages/memory-engine/package.json +1 -1
  125. package/packages/milestone-manager/package.json +1 -1
  126. package/packages/model-registry/package.json +1 -1
  127. package/packages/nextjs-plugin/package.json +1 -1
  128. package/packages/notification/package.json +1 -1
  129. package/packages/observability/package.json +1 -1
  130. package/packages/okf-indexer/package.json +1 -1
  131. package/packages/performance-optimizer/package.json +1 -1
  132. package/packages/privilege-broker/package.json +1 -1
  133. package/packages/project-analyzer/package.json +1 -1
  134. package/packages/project-bootstrap/package.json +1 -1
  135. package/packages/projection-engine/package.json +1 -1
  136. package/packages/prompt-compiler/package.json +1 -1
  137. package/packages/prompt-versioning/package.json +1 -1
  138. package/packages/provider-adapter-sdk/package.json +1 -1
  139. package/packages/provider-router/package.json +1 -1
  140. package/packages/provider-selector/package.json +1 -1
  141. package/packages/providers/package.json +1 -1
  142. package/packages/quota-manager/package.json +1 -1
  143. package/packages/rate-limiter/package.json +1 -1
  144. package/packages/react-vite-plugin/package.json +1 -1
  145. package/packages/release-manager/package.json +1 -1
  146. package/packages/requirement-compiler/package.json +1 -1
  147. package/packages/runtime/package.json +1 -1
  148. package/packages/scheduler/package.json +1 -1
  149. package/packages/scheduler-adapter/package.json +1 -1
  150. package/packages/session/package.json +1 -1
  151. package/packages/session-api/package.json +1 -1
  152. package/packages/session-export/package.json +1 -1
  153. package/packages/shared-context/package.json +1 -1
  154. package/packages/skill-mcp-client/package.json +1 -1
  155. package/packages/skill-registry/package.json +1 -1
  156. package/packages/sprint-planner/package.json +1 -1
  157. package/packages/subscription-engine/package.json +1 -1
  158. package/packages/task-compiler/package.json +1 -1
  159. package/packages/tencentdb-memory/package.json +1 -1
  160. package/packages/tencentdb-sync/package.json +1 -1
  161. package/packages/test-data-generator/package.json +1 -1
  162. package/packages/test-generator/package.json +1 -1
  163. package/packages/todo-bd-sync/README.md +71 -0
  164. package/packages/todo-bd-sync/package.json +1 -1
  165. package/packages/todo-bd-sync/src/extension.ts +16 -1
  166. package/packages/token-estimation/package.json +1 -1
  167. package/packages/token-optimizer/package.json +1 -1
  168. package/packages/trajectory/dist/src/approved-patterns.d.ts +51 -0
  169. package/packages/trajectory/dist/src/approved-patterns.d.ts.map +1 -0
  170. package/packages/trajectory/dist/src/approved-patterns.js +134 -0
  171. package/packages/trajectory/dist/src/approved-patterns.js.map +1 -0
  172. package/packages/trajectory/dist/src/index.d.ts +13 -0
  173. package/packages/trajectory/dist/src/index.d.ts.map +1 -0
  174. package/packages/trajectory/dist/src/index.js +12 -0
  175. package/packages/trajectory/dist/src/index.js.map +1 -0
  176. package/packages/trajectory/dist/src/store.d.ts +69 -0
  177. package/packages/trajectory/dist/src/store.d.ts.map +1 -0
  178. package/packages/trajectory/dist/src/store.js +253 -0
  179. package/packages/trajectory/dist/src/store.js.map +1 -0
  180. package/packages/trajectory/dist/src/types.d.ts +73 -0
  181. package/packages/trajectory/dist/src/types.d.ts.map +1 -0
  182. package/packages/trajectory/dist/src/types.js +9 -0
  183. package/packages/trajectory/dist/src/types.js.map +1 -0
  184. package/packages/trajectory/dist/test/store.test.d.ts +2 -0
  185. package/packages/trajectory/dist/test/store.test.d.ts.map +1 -0
  186. package/packages/trajectory/dist/test/store.test.js +228 -0
  187. package/packages/trajectory/dist/test/store.test.js.map +1 -0
  188. package/packages/trajectory/package.json +29 -0
  189. package/packages/trajectory/src/approved-patterns.ts +180 -0
  190. package/packages/trajectory/src/index.ts +26 -0
  191. package/packages/trajectory/src/store.ts +285 -0
  192. package/packages/trajectory/src/types.ts +84 -0
  193. package/packages/trajectory/test/store.test.d.ts +2 -0
  194. package/packages/trajectory/test/store.test.ts +250 -0
  195. package/packages/tui/package.json +1 -1
  196. package/packages/types/package.json +1 -1
  197. package/packages/workflow-events/package.json +1 -1
  198. package/packages/workspace-scanner/package.json +1 -1
  199. package/packages/worktree/package.json +1 -1
  200. package/packages/write-review/package.json +1 -1
  201. package/packages/write-review/src/blackboard.ts +38 -5
  202. package/packages/write-review/src/types.ts +13 -0
  203. package/skills/harness-runtime/SKILL.md +67 -4
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Flaky Detector - Specialized module for detecting flaky tests
3
+ *
4
+ * Uses Jev to analyze test failures and determine if they're flaky.
5
+ */
6
+
7
+ import { JevJudge } from "./index.js";
8
+ import type { JevJudgeConfig, E2ETestResult, E2EFlakyAnalysis } from "./types.js";
9
+
10
+ // Known flaky patterns
11
+ const FLAKY_PATTERNS = {
12
+ timeout: ["timeout", "timed out", "ETIMEDOUT", "TimeoutError"],
13
+ network: ["ECONNREFUSED", "ENOTFOUND", "network", "fetch failed"],
14
+ race_condition: [
15
+ "race condition",
16
+ "concurrent",
17
+ "simultaneous",
18
+ "out of order",
19
+ ],
20
+ ui_state: [
21
+ "element not visible",
22
+ "element not interactable",
23
+ "stale element",
24
+ "not attached",
25
+ ],
26
+ };
27
+
28
+ /**
29
+ * Flaky Detector - Specialized for detecting flaky test failures
30
+ */
31
+ export class FlakyDetector {
32
+ private judge: JevJudge;
33
+ private threshold: number;
34
+
35
+ constructor(config: JevJudgeConfig, threshold = 0.7) {
36
+ this.judge = new JevJudge(config);
37
+ this.threshold = threshold;
38
+ }
39
+
40
+ /**
41
+ * Quick pattern-based flaky detection (without Jev)
42
+ * Used for fast, synchronous checks
43
+ */
44
+ detectPattern(errorMessage?: string): {
45
+ isFlaky: boolean;
46
+ pattern: string | null;
47
+ confidence: "high" | "medium" | "low";
48
+ } {
49
+ if (!errorMessage) {
50
+ return {
51
+ isFlaky: false,
52
+ pattern: null,
53
+ confidence: "low",
54
+ };
55
+ }
56
+
57
+ const lowerError = errorMessage.toLowerCase();
58
+
59
+ for (const [pattern, keywords] of Object.entries(FLAKY_PATTERNS)) {
60
+ const matches = keywords.filter((kw) => lowerError.includes(kw.toLowerCase()));
61
+
62
+ if (matches.length > 0) {
63
+ return {
64
+ isFlaky: true,
65
+ pattern,
66
+ confidence: matches.length >= 2 ? "high" : "medium",
67
+ };
68
+ }
69
+ }
70
+
71
+ return {
72
+ isFlaky: false,
73
+ pattern: null,
74
+ confidence: "low",
75
+ };
76
+ }
77
+
78
+ /**
79
+ * AI-powered flaky detection with Jev
80
+ */
81
+ async detect(testResult: E2ETestResult): Promise<E2EFlakyAnalysis> {
82
+ // First, quick pattern check
83
+ const patternResult = this.detectPattern(testResult.error);
84
+
85
+ // If pattern detection is confident, return early
86
+ if (patternResult.confidence === "high") {
87
+ return {
88
+ isFlaky: patternResult.isFlaky,
89
+ confidence: patternResult.confidence,
90
+ probability: patternResult.isFlaky ? 0.95 : 0.05,
91
+ pattern: patternResult.pattern ?? undefined,
92
+ recommendation: patternResult.isFlaky ? "skip" : "investigate",
93
+ };
94
+ }
95
+
96
+ // Use Jev for nuanced analysis
97
+ const state = this.buildState(testResult);
98
+
99
+ const result = await this.judge.evaluate(state, {
100
+ isFlaky: {
101
+ type: "noul",
102
+ instructions:
103
+ "Does this failure match a known flaky pattern? Consider: timeout, network issue, race condition, or intermittent UI state.",
104
+ },
105
+ patternType: {
106
+ type: "choice",
107
+ instructions: "What is the most likely cause?",
108
+ options: [
109
+ "timeout",
110
+ "network_issue",
111
+ "race_condition",
112
+ "ui_intermittent",
113
+ "resource_contention",
114
+ "real_bug",
115
+ "unknown",
116
+ ],
117
+ },
118
+ confidence: {
119
+ type: "noul",
120
+ instructions:
121
+ "Is this assessment based on clear evidence and likely to be correct?",
122
+ },
123
+ });
124
+
125
+ const isFlakyDecision = result.decisions.isFlaky;
126
+ const probability = isFlakyDecision.probability ?? 0.5;
127
+
128
+ const patternDecision = result.decisions.patternType as {
129
+ response: { choice: string };
130
+ };
131
+
132
+ return {
133
+ isFlaky: probability >= this.threshold,
134
+ confidence: isFlakyDecision.confidence,
135
+ probability,
136
+ pattern: patternDecision?.response?.choice,
137
+ recommendation: this.getRecommendation(probability),
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Batch detect flaky tests
143
+ */
144
+ async batchDetect(
145
+ testResults: E2ETestResult[]
146
+ ): Promise<Map<string, E2EFlakyAnalysis>> {
147
+ const results = new Map<string, E2EFlakyAnalysis>();
148
+
149
+ // Process in batches
150
+ const BATCH_SIZE = 5;
151
+ for (let i = 0; i < testResults.length; i += BATCH_SIZE) {
152
+ const batch = testResults.slice(i, i + BATCH_SIZE);
153
+
154
+ const batchResults = await Promise.all(
155
+ batch.map((test) => this.detect(test))
156
+ );
157
+
158
+ for (let j = 0; j < batch.length; j++) {
159
+ results.set(batch[j].name, batchResults[j]);
160
+ }
161
+ }
162
+
163
+ return results;
164
+ }
165
+
166
+ private buildState(test: E2ETestResult): string {
167
+ const parts: string[] = [`Test: ${test.name}`, `Status: ${test.status}`];
168
+
169
+ if (test.error) {
170
+ parts.push(`Error: ${test.error}`);
171
+ }
172
+
173
+ if (test.duration !== undefined) {
174
+ parts.push(`Duration: ${test.duration}ms`);
175
+ }
176
+
177
+ if (test.retries !== undefined) {
178
+ parts.push(`Previous retries: ${test.retries}`);
179
+ }
180
+
181
+ return parts.join("\n");
182
+ }
183
+
184
+ private getRecommendation(probability: number): "retry" | "skip" | "block" | "investigate" {
185
+ if (probability >= 0.9) return "skip";
186
+ if (probability >= 0.7) return "retry";
187
+ if (probability >= 0.4) return "investigate";
188
+ return "block";
189
+ }
190
+ }
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Jev Judge - Main API
3
+ *
4
+ * Structured decision model for agent routing, E2E testing, and automated decisions.
5
+ * Uses TypeSafe Jev via OpenRouter for fast, calibrated, hallucination-free decisions.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { JevJudge } from "@pi-harness/jev-judge";
10
+ *
11
+ * const judge = new JevJudge({ apiKey: process.env.OPENROUTER_API_KEY! });
12
+ *
13
+ * // Ask multiple questions at once
14
+ * const result = await judge.evaluate(
15
+ * "The deploy failed with exit code 1",
16
+ * {
17
+ * isUrgent: { type: "noul", instructions: "Does this require immediate attention?" },
18
+ * severity: {
19
+ * type: "choice",
20
+ * instructions: "What is the severity level?",
21
+ * options: ["critical", "high", "medium", "low"]
22
+ * }
23
+ * }
24
+ * );
25
+ *
26
+ * console.log(result.decisions.isUrgent.noul); // 0.92
27
+ * ```
28
+ */
29
+
30
+ import type {
31
+ JevJudgeConfig,
32
+ JevQuestion,
33
+ JevQuestions,
34
+ JevResponse,
35
+ JevDecision,
36
+ JevEvaluationResult,
37
+ JevNoulResponse,
38
+ JevChoiceResponse,
39
+ JevScoreResponse,
40
+ ThresholdDecision,
41
+ } from "./types.js";
42
+
43
+ // OpenAI SDK (OpenRouter is OpenAI-compatible)
44
+ // @ts-ignore - openai is installed at workspace root
45
+ import OpenAI from "openai";
46
+
47
+ /**
48
+ * Default configuration
49
+ */
50
+ const DEFAULT_CONFIG = {
51
+ baseUrl: "https://openrouter.ai/api/v1",
52
+ model: "typesafe/jev-1.13",
53
+ defaultThreshold: 0.7,
54
+ timeoutMs: 30000,
55
+ };
56
+
57
+ /**
58
+ * JevJudge - Main class for making structured decisions with Jev
59
+ */
60
+ export class JevJudge {
61
+ private client: OpenAI;
62
+ private config: Required<JevJudgeConfig>;
63
+
64
+ constructor(config: JevJudgeConfig) {
65
+ this.config = {
66
+ ...DEFAULT_CONFIG,
67
+ ...config,
68
+ } as Required<JevJudgeConfig>;
69
+
70
+ this.client = new OpenAI({
71
+ apiKey: this.config.apiKey,
72
+ baseURL: this.config.baseUrl,
73
+ timeout: this.config.timeoutMs,
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Evaluate state against questions
79
+ *
80
+ * @param state - The context/situation to evaluate (text or structured)
81
+ * @param questions - Map of question_id -> question definition
82
+ * @returns Evaluation result with decisions
83
+ */
84
+ async evaluate<T extends string>(
85
+ state: string | object,
86
+ questions: JevQuestions<T>
87
+ ): Promise<JevEvaluationResult<T>> {
88
+ const startTime = Date.now();
89
+
90
+ // Convert state to string if object
91
+ const stateStr = typeof state === "string" ? state : JSON.stringify(state);
92
+
93
+ // Build questions array for API
94
+ const questionsArray = Object.entries(questions).map(([id, q]) => {
95
+ const questionObj = q as JevQuestion;
96
+ const entry: Record<string, unknown> = { id };
97
+ if (questionObj.type === "noul") {
98
+ entry.type = "noul";
99
+ entry.instructions = questionObj.instructions;
100
+ } else if (questionObj.type === "choice") {
101
+ entry.type = "choice";
102
+ entry.instructions = questionObj.instructions;
103
+ entry.options = questionObj.options;
104
+ } else if (questionObj.type === "score") {
105
+ entry.type = "score";
106
+ entry.instructions = questionObj.instructions;
107
+ if (questionObj.min !== undefined) entry.min = questionObj.min;
108
+ if (questionObj.max !== undefined) entry.max = questionObj.max;
109
+ }
110
+ return entry;
111
+ });
112
+
113
+ // Call Jev via OpenRouter
114
+ const response = await this.client.chat.completions.create({
115
+ model: this.config.model,
116
+ messages: [
117
+ {
118
+ role: "system",
119
+ content: `You are a decision engine. Evaluate the following state and answer the questions.
120
+ Return your answers in the exact JSON format specified.`,
121
+ },
122
+ {
123
+ role: "user",
124
+ content: `State: ${stateStr}
125
+
126
+ Questions:
127
+ ${JSON.stringify(questionsArray, null, 2)}
128
+
129
+ Respond with a JSON object mapping each question ID to its answer.`,
130
+ },
131
+ ],
132
+ response_format: {
133
+ type: "json_object",
134
+ schema: this.buildResponseSchema(questions),
135
+ },
136
+ temperature: 0.1, // Low temperature for consistent decisions
137
+ });
138
+
139
+ const latencyMs = Date.now() - startTime;
140
+
141
+ // Parse response
142
+ const content = response.choices[0]?.message?.content;
143
+ if (!content) {
144
+ throw new Error("No response from Jev");
145
+ }
146
+
147
+ let parsed: Record<string, unknown>;
148
+ try {
149
+ parsed = JSON.parse(content);
150
+ } catch {
151
+ throw new Error("Invalid JSON response from Jev");
152
+ }
153
+
154
+ // Build decisions map
155
+ const decisions = {} as Record<T, JevDecision<T>>;
156
+
157
+ for (const [questionId, question] of Object.entries(questions)) {
158
+ const questionData = question as JevQuestion;
159
+ const responseData = (parsed as Record<string, unknown>)[questionId] as
160
+ | JevResponse
161
+ | undefined;
162
+
163
+ if (!responseData) {
164
+ continue;
165
+ }
166
+
167
+ const decision = this.buildDecision(
168
+ questionId,
169
+ questionData,
170
+ responseData
171
+ );
172
+ (decisions as Record<string, JevDecision>)[questionId] = decision;
173
+ }
174
+
175
+ return {
176
+ decisions,
177
+ state: stateStr,
178
+ latencyMs,
179
+ model: this.config.model,
180
+ };
181
+ }
182
+
183
+ /**
184
+ * Quick noul (yes/no) evaluation
185
+ */
186
+ async noul(
187
+ state: string | object,
188
+ question: string
189
+ ): Promise<{ noul: number; confidence: "high" | "medium" | "low" }> {
190
+ const result = await this.evaluate(state, {
191
+ answer: { type: "noul", instructions: question },
192
+ });
193
+
194
+ const decision = result.decisions.answer as JevDecision<"answer">;
195
+ return {
196
+ noul: (decision.response as JevNoulResponse).noul,
197
+ confidence: decision.confidence,
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Quick choice evaluation
203
+ */
204
+ async choice<T extends string>(
205
+ state: string | object,
206
+ question: string,
207
+ options: T[]
208
+ ): Promise<{ choice: T; confidence: number }> {
209
+ const result = await this.evaluate(state, {
210
+ answer: { type: "choice", instructions: question, options },
211
+ });
212
+
213
+ const decision = result.decisions.answer as JevDecision<"answer">;
214
+ return {
215
+ choice: (decision.response as JevChoiceResponse<T>).choice,
216
+ confidence: (decision.response as JevChoiceResponse).confidence,
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Make threshold-based decision
222
+ */
223
+ thresholdDecision(
224
+ probability: number,
225
+ threshold: number = this.config.defaultThreshold
226
+ ): ThresholdDecision {
227
+ const confidence = this.getConfidence(probability, threshold);
228
+
229
+ return {
230
+ shouldAct: probability >= threshold,
231
+ probability,
232
+ confidence,
233
+ action: probability >= 0.9 ? "proceed" : probability >= 0.5 ? "review" : "block",
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Batch evaluate multiple states
239
+ */
240
+ async batchEvaluate<T extends string>(
241
+ states: (string | object)[],
242
+ questions: JevQuestions<T>,
243
+ options: { concurrency?: number } = {}
244
+ ): Promise<JevEvaluationResult<T>[]> {
245
+ const { concurrency = 3 } = options;
246
+
247
+ const results: JevEvaluationResult<T>[] = [];
248
+ const batches: (string | object)[] = [];
249
+
250
+ // Split into batches
251
+ for (let i = 0; i < states.length; i += concurrency) {
252
+ batches.push(...states.slice(i, i + concurrency));
253
+ }
254
+
255
+ // Process batches
256
+ for (const batch of batches) {
257
+ const result = await this.evaluate(batch, questions);
258
+ results.push(result);
259
+ }
260
+
261
+ return results;
262
+ }
263
+
264
+ // Private helpers
265
+
266
+ private buildResponseSchema(questions: JevQuestions): Record<string, unknown> {
267
+ const schema: Record<string, unknown> = {};
268
+
269
+ for (const [id, question] of Object.entries(questions)) {
270
+ switch ((question as JevQuestion).type) {
271
+ case "noul":
272
+ schema[id] = { type: "object", properties: {
273
+ noul: { type: "number", minimum: 0, maximum: 1 }
274
+ }, required: ["noul"] };
275
+ break;
276
+ case "choice":
277
+ schema[id] = { type: "object", properties: {
278
+ choice: { type: "string", enum: (question as { options: string[] }).options },
279
+ confidence: { type: "number", minimum: 0, maximum: 1 }
280
+ }, required: ["choice"] };
281
+ break;
282
+ case "score":
283
+ schema[id] = { type: "object", properties: {
284
+ score: { type: "number" },
285
+ confidence: { type: "number", minimum: 0, maximum: 1 }
286
+ }, required: ["score"] };
287
+ break;
288
+ }
289
+ }
290
+
291
+ return { type: "object", properties: schema, additionalProperties: false };
292
+ }
293
+
294
+ private buildDecision<T extends string>(
295
+ questionId: T,
296
+ question: JevQuestion,
297
+ response: JevResponse
298
+ ): JevDecision<T> {
299
+ let probability: number;
300
+ let confidence: "high" | "medium" | "low";
301
+
302
+ switch (response.type) {
303
+ case "noul":
304
+ probability = response.noul;
305
+ break;
306
+ case "choice":
307
+ probability = response.confidence;
308
+ break;
309
+ case "score":
310
+ // Normalize score to 0-1
311
+ const max = question.type === "score" ? (question.max ?? 100) : 100;
312
+ const min = question.type === "score" ? (question.min ?? 0) : 0;
313
+ probability = (response.score - min) / (max - min);
314
+ break;
315
+ }
316
+
317
+ confidence = this.getConfidence(probability, this.config.defaultThreshold);
318
+
319
+ return {
320
+ questionId,
321
+ question,
322
+ response,
323
+ probability,
324
+ confidence,
325
+ };
326
+ }
327
+
328
+ private getConfidence(
329
+ probability: number,
330
+ threshold: number
331
+ ): "high" | "medium" | "low" {
332
+ const distance = Math.abs(probability - threshold);
333
+ if (distance > 0.3) return "high";
334
+ if (distance > 0.15) return "medium";
335
+ return "low";
336
+ }
337
+ }
338
+
339
+ // Export types
340
+ export * from "./types.js";
341
+
342
+ // Export submodules
343
+ export { E2EJudge } from "./e2e-judge.js";
344
+ export { FlakyDetector } from "./flaky-detector.js";
345
+ export { DecisionEngine } from "./decision-engine.js";
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Jev Judge - Type definitions
3
+ *
4
+ * Jev is a System One model from TypeSafe AI that makes fast, structured decisions
5
+ * with calibrated probabilities. Available via OpenRouter: typesafe/jev-1.13
6
+ */
7
+
8
+ // Question types supported by Jev
9
+ export type JevQuestionType = "noul" | "choice" | "score";
10
+
11
+ // Noul: Yes/No question (returns probability 0-1)
12
+ export interface JevNoulQuestion {
13
+ type: "noul";
14
+ instructions: string;
15
+ }
16
+
17
+ // Choice: Select from options (returns selected option)
18
+ export interface JevChoiceQuestion<T extends string = string> {
19
+ type: "choice";
20
+ instructions: string;
21
+ options: T[];
22
+ }
23
+
24
+ // Score: Rate something 0-100
25
+ export interface JevScoreQuestion {
26
+ type: "score";
27
+ instructions: string;
28
+ min?: number;
29
+ max?: number;
30
+ }
31
+
32
+ // Any question type
33
+ export type JevQuestion = JevNoulQuestion | JevChoiceQuestion | JevScoreQuestion;
34
+
35
+ // Questions map (question_id -> question)
36
+ export type JevQuestions<T extends string = string> = Partial<
37
+ Record<T, JevQuestion>
38
+ >;
39
+
40
+ // Response types
41
+ export interface JevNoulResponse {
42
+ type: "noul";
43
+ noul: number; // 0-1 probability
44
+ }
45
+
46
+ export interface JevChoiceResponse<T extends string = string> {
47
+ type: "choice";
48
+ choice: T;
49
+ confidence: number; // 0-1
50
+ }
51
+
52
+ export interface JevScoreResponse {
53
+ type: "score";
54
+ score: number;
55
+ confidence: number; // 0-1
56
+ }
57
+
58
+ // Any response type
59
+ export type JevResponse = JevNoulResponse | JevChoiceResponse | JevScoreResponse;
60
+
61
+ // Response map
62
+ export type JevResponses<T extends string = string> = Partial<Record<T, JevResponse>>;
63
+
64
+ // Decision result with metadata
65
+ export interface JevDecision<T extends string = string> {
66
+ questionId: T;
67
+ question: JevQuestion;
68
+ response: JevResponse;
69
+ probability?: number; // Extracted for easy access (noul = noul value, choice = confidence)
70
+ confidence: "high" | "medium" | "low";
71
+ }
72
+
73
+ // Full evaluation result
74
+ export interface JevEvaluationResult<T extends string = string> {
75
+ decisions: Record<T, JevDecision<T>>;
76
+ state: string;
77
+ latencyMs: number;
78
+ model: string;
79
+ }
80
+
81
+ // Threshold-based action decision
82
+ export interface ThresholdDecision {
83
+ shouldAct: boolean;
84
+ probability: number;
85
+ confidence: "high" | "medium" | "low";
86
+ action: "proceed" | "review" | "block";
87
+ }
88
+
89
+ // Config
90
+ export interface JevJudgeConfig {
91
+ apiKey: string;
92
+ baseUrl?: string; // Defaults to OpenRouter
93
+ model?: string; // Defaults to typesafe/jev-1.13
94
+ defaultThreshold?: number; // Default 0.7
95
+ timeoutMs?: number;
96
+ }
97
+
98
+ // E2E Test Judge types
99
+ export interface E2ETestResult {
100
+ name: string;
101
+ status: "passed" | "failed" | "skipped" | "pending";
102
+ duration?: number; // ms
103
+ error?: string;
104
+ screenshot?: string;
105
+ consoleLogs?: string[];
106
+ networkLogs?: string[];
107
+ retries?: number;
108
+ }
109
+
110
+ export interface E2EFlakyAnalysis {
111
+ isFlaky: boolean;
112
+ confidence: "high" | "medium" | "low";
113
+ probability: number;
114
+ pattern?: string;
115
+ recommendation: "retry" | "skip" | "block" | "investigate";
116
+ }
117
+
118
+ export interface E2EBuildDecision {
119
+ shouldBlock: boolean;
120
+ probability: number;
121
+ confidence: "high" | "medium" | "low";
122
+ reason: string;
123
+ affectedTests: string[];
124
+ }
125
+
126
+ export interface E2ERetryDecision {
127
+ shouldRetry: boolean;
128
+ maxAttempts: number;
129
+ probability: number;
130
+ delayMs?: number;
131
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/knowledge-graph",
3
- "version": "1.1.49",
3
+ "version": "1.1.71-3",
4
4
  "description": "Knowledge Graph extraction and provenance linking for SKILL.md files",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/knowledge-retrieval",
3
- "version": "1.1.49",
3
+ "version": "1.1.71-3",
4
4
  "description": "Knowledge retrieval via TencentDB-Agent-Memory MCP (RFC-0105)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/laravel-plugin",
3
- "version": "1.1.49",
3
+ "version": "1.1.71-3",
4
4
  "description": "Laravel framework analysis — artisan commands, Eloquent models, Blade",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/learning-engine",
3
- "version": "1.1.49",
3
+ "version": "1.1.71-3",
4
4
  "description": "Learning engine for extracting lessons from runtime execution (RFC-0058)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/mcp-adapter",
3
- "version": "1.1.49",
3
+ "version": "1.1.71-3",
4
4
  "type": "module",
5
5
  "description": "MCP server adapter for pi-harness — exposes harness capabilities as MCP tools/resources/prompts (RFC-0068)",
6
6
  "main": "dist/index.js",