@harness-engineering/intelligence 0.2.7 → 0.3.1

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.
package/dist/index.mjs CHANGED
@@ -106,6 +106,105 @@ function manualToRawWorkItem(input) {
106
106
  };
107
107
  }
108
108
 
109
+ // src/adapters/canary.ts
110
+ import { z } from "zod";
111
+ import { execFile } from "child_process";
112
+ var frameworkRecommendationSchema = z.object({
113
+ status: z.string(),
114
+ test_type: z.string(),
115
+ framework: z.string(),
116
+ file_extension: z.string(),
117
+ reasoning: z.array(z.string()),
118
+ alternatives: z.array(z.string())
119
+ });
120
+ var canaryFindingSchema = z.object({
121
+ file: z.string(),
122
+ line: z.number(),
123
+ rule: z.string(),
124
+ severity: z.string(),
125
+ message: z.string(),
126
+ suggestion: z.string()
127
+ });
128
+ var canaryFindingsSchema = z.array(canaryFindingSchema);
129
+ var EXEC_TIMEOUT_MS = 3e4;
130
+ var EXEC_MAX_BUFFER = 16 * 1024 * 1024;
131
+ var defaultExec = (cmd, args) => new Promise((resolve, reject) => {
132
+ execFile(
133
+ cmd,
134
+ args,
135
+ { encoding: "utf8", timeout: EXEC_TIMEOUT_MS, maxBuffer: EXEC_MAX_BUFFER },
136
+ (err, stdout) => {
137
+ if (err) {
138
+ reject(err);
139
+ return;
140
+ }
141
+ resolve({ stdout });
142
+ }
143
+ );
144
+ });
145
+ function canaryInvocation(subArgs) {
146
+ return ["canary", subArgs];
147
+ }
148
+ function parseVersion(stdout) {
149
+ return stdout.match(/\d+\.\d+\.\d+/)?.[0];
150
+ }
151
+ function safeJson(stdout) {
152
+ try {
153
+ return JSON.parse(stdout);
154
+ } catch {
155
+ return void 0;
156
+ }
157
+ }
158
+ function degradedRecommendation() {
159
+ return {
160
+ status: "degraded",
161
+ test_type: "",
162
+ framework: "",
163
+ file_extension: "",
164
+ reasoning: [],
165
+ alternatives: []
166
+ };
167
+ }
168
+ function createCanaryAdapter(exec = defaultExec) {
169
+ async function execCanary(subArgs) {
170
+ const [cmd, args] = canaryInvocation(subArgs);
171
+ try {
172
+ const { stdout } = await exec(cmd, args);
173
+ return { ok: true, stdout };
174
+ } catch (err) {
175
+ const e = err;
176
+ if (e.code === "ENOENT") return { ok: false, reason: "not-installed" };
177
+ if (e.code === 1 && /canary binary not found/i.test(e.stderr ?? "")) {
178
+ return { ok: false, reason: "binary-missing" };
179
+ }
180
+ return { ok: false, reason: "exec-failed" };
181
+ }
182
+ }
183
+ let cachedProbe;
184
+ const probe = () => cachedProbe ??= (async () => {
185
+ const res = await execCanary(["version"]);
186
+ if (!res.ok) return { status: "degraded", reason: res.reason };
187
+ if (res.stdout.trim() === "") return { status: "degraded", reason: "bad-output" };
188
+ const version = parseVersion(res.stdout);
189
+ return version ? { status: "available", version } : { status: "available" };
190
+ })();
191
+ const recommendFramework = async (prompt) => {
192
+ const res = await execCanary(["recommend", prompt, "--json"]);
193
+ if (!res.ok) return degradedRecommendation();
194
+ const parsed = frameworkRecommendationSchema.safeParse(safeJson(res.stdout));
195
+ return parsed.success ? parsed.data : degradedRecommendation();
196
+ };
197
+ const reviewTest = async (path2, framework) => {
198
+ const args = ["review-test", path2, "--json"];
199
+ if (framework) args.push("--framework", framework);
200
+ const res = await execCanary(args);
201
+ if (!res.ok) return [];
202
+ const parsed = canaryFindingsSchema.safeParse(safeJson(res.stdout));
203
+ return parsed.success ? parsed.data : [];
204
+ };
205
+ return { probe, recommendFramework, reviewTest };
206
+ }
207
+
109
208
  // src/analysis-provider/anthropic.ts
110
209
  import Anthropic from "@anthropic-ai/sdk";
111
210
 
@@ -397,7 +496,7 @@ ${request.prompt}` : request.prompt;
397
496
  };
398
497
 
399
498
  // src/sel/prompts.ts
400
- import { z } from "zod";
499
+ import { z as z2 } from "zod";
401
500
  var SEL_SYSTEM_PROMPT = `You are a spec enrichment agent. Your job is to analyze a work item (feature request, bug report, task, etc.) and produce structured output that captures the full engineering intent.
402
501
 
403
502
  Analyze the provided work item and extract:
@@ -461,22 +560,22 @@ ${metaEntries.map(([k, v]) => `- **${k}:** ${String(v)}`).join("\n")}`
461
560
  }
462
561
  return parts.join("\n");
463
562
  }
464
- var selResponseSchema = z.object({
465
- intent: z.string(),
466
- summary: z.string(),
467
- affectedSystems: z.array(z.object({ name: z.string() })),
468
- functionalRequirements: z.array(z.string()),
469
- nonFunctionalRequirements: z.array(z.string()),
470
- apiChanges: z.array(z.string()),
471
- dbChanges: z.array(z.string()),
472
- integrationPoints: z.array(z.string()),
473
- assumptions: z.array(z.string()),
474
- unknowns: z.array(z.string()),
475
- ambiguities: z.array(z.string()),
476
- riskSignals: z.array(z.string()),
477
- initialComplexityHints: z.object({
478
- textualComplexity: z.number().min(0).max(1),
479
- structuralComplexity: z.number().min(0).max(1)
563
+ var selResponseSchema = z2.object({
564
+ intent: z2.string(),
565
+ summary: z2.string(),
566
+ affectedSystems: z2.array(z2.object({ name: z2.string() })),
567
+ functionalRequirements: z2.array(z2.string()),
568
+ nonFunctionalRequirements: z2.array(z2.string()),
569
+ apiChanges: z2.array(z2.string()),
570
+ dbChanges: z2.array(z2.string()),
571
+ integrationPoints: z2.array(z2.string()),
572
+ assumptions: z2.array(z2.string()),
573
+ unknowns: z2.array(z2.string()),
574
+ ambiguities: z2.array(z2.string()),
575
+ riskSignals: z2.array(z2.string()),
576
+ initialComplexityHints: z2.object({
577
+ textualComplexity: z2.number().min(0).max(1),
578
+ structuralComplexity: z2.number().min(0).max(1)
480
579
  })
481
580
  });
482
581
 
@@ -850,7 +949,7 @@ function runGraphOnlyChecks(spec, score2, store) {
850
949
  }
851
950
 
852
951
  // src/pesl/prompts.ts
853
- import { z as z2 } from "zod";
952
+ import { z as z3 } from "zod";
854
953
  var PESL_SYSTEM_PROMPT = `You are a pre-execution simulation agent. Your job is to analyze an enriched specification and its complexity assessment, then simulate what would happen if an autonomous coding agent attempted to implement this change.
855
954
 
856
955
  Your simulation should:
@@ -862,13 +961,13 @@ Your simulation should:
862
961
  Be realistic and specific. Reference actual system names from the spec. Err on the side of flagging potential issues -- it is better to over-predict failures than to miss them.
863
962
 
864
963
  Return your analysis using the structured_output tool.`;
865
- var peslResponseSchema = z2.object({
866
- simulatedPlan: z2.array(z2.string()).describe("Ordered implementation steps the agent would take"),
867
- predictedFailures: z2.array(z2.string()).describe("Likely failure modes during implementation"),
868
- riskHotspots: z2.array(z2.string()).describe("Files or modules that are high-risk change points"),
869
- missingSteps: z2.array(z2.string()).describe("Steps the agent might miss or overlook"),
870
- testGaps: z2.array(z2.string()).describe("Tests that should exist but likely do not"),
871
- recommendedChanges: z2.array(z2.string()).describe("Adjustments to improve success likelihood")
964
+ var peslResponseSchema = z3.object({
965
+ simulatedPlan: z3.array(z3.string()).describe("Ordered implementation steps the agent would take"),
966
+ predictedFailures: z3.array(z3.string()).describe("Likely failure modes during implementation"),
967
+ riskHotspots: z3.array(z3.string()).describe("Files or modules that are high-risk change points"),
968
+ missingSteps: z3.array(z3.string()).describe("Steps the agent might miss or overlook"),
969
+ testGaps: z3.array(z3.string()).describe("Tests that should exist but likely do not"),
970
+ recommendedChanges: z3.array(z3.string()).describe("Adjustments to improve success likelihood")
872
971
  });
873
972
  function appendSection(parts, heading, items) {
874
973
  if (items.length === 0) return;
@@ -1006,6 +1105,30 @@ var PeslSimulator = class {
1006
1105
  };
1007
1106
 
1008
1107
  // src/outcome/connector.ts
1108
+ var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([
1109
+ "id",
1110
+ "identifier",
1111
+ "type",
1112
+ "name",
1113
+ "result",
1114
+ "retryCount",
1115
+ "failureReasons",
1116
+ "durationMs",
1117
+ "linkedSpecId",
1118
+ "timestamp",
1119
+ "issueId",
1120
+ "agentPersona",
1121
+ "taskType",
1122
+ "affectedSystemNodeIds",
1123
+ "edges"
1124
+ ]);
1125
+ function stripReservedKeys(metadata) {
1126
+ const safe = {};
1127
+ for (const [key, value] of Object.entries(metadata)) {
1128
+ if (!RESERVED_METADATA_KEYS.has(key)) safe[key] = value;
1129
+ }
1130
+ return safe;
1131
+ }
1009
1132
  var ExecutionOutcomeConnector = class {
1010
1133
  constructor(store) {
1011
1134
  this.store = store;
@@ -1018,6 +1141,11 @@ var ExecutionOutcomeConnector = class {
1018
1141
  type: "execution_outcome",
1019
1142
  name: `${outcome.result}: ${outcome.identifier}`,
1020
1143
  metadata: {
1144
+ // Caller-supplied extras are STRIPPED of all reserved/core keys before
1145
+ // merge, so they can never shadow a core field — even conditionally-
1146
+ // written ones like agentPersona/taskType. Only genuinely additive
1147
+ // keys (e.g. verdict/confidence/source) survive.
1148
+ ...stripReservedKeys(outcome.metadata ?? {}),
1021
1149
  issueId: outcome.issueId,
1022
1150
  identifier: outcome.identifier,
1023
1151
  result: outcome.result,
@@ -1045,6 +1173,256 @@ var ExecutionOutcomeConnector = class {
1045
1173
  }
1046
1174
  };
1047
1175
 
1176
+ // src/outcome-eval/authority.ts
1177
+ function deriveAuthority(verdict, confidence) {
1178
+ return verdict === "NOT_SATISFIED" && confidence === "high" ? "blocking" : "advisory";
1179
+ }
1180
+
1181
+ // src/outcome-eval/prompts.ts
1182
+ import { z as z4 } from "zod";
1183
+ var verdictSchema = z4.object({
1184
+ verdict: z4.enum(["SATISFIED", "NOT_SATISFIED", "INCONCLUSIVE"]).describe("Whether the change satisfies the judged spec section"),
1185
+ confidence: z4.enum(["low", "medium", "high"]).describe("Confidence in the verdict; high requires a named criterion"),
1186
+ rationale: z4.string().describe("Cites specific met / unmet criteria"),
1187
+ unmetCriteria: z4.array(z4.string()).describe("Unmet criteria; empty when SATISFIED")
1188
+ }).strict();
1189
+ var OUTCOME_EVAL_SYSTEM_PROMPT = `You are a post-execution outcome judge. Given a spec acceptance section, a unified diff, and test output, decide whether the change SATISFIED, NOT_SATISFIED, or is INCONCLUSIVE against that section.
1190
+
1191
+ Confidence calibration (be conservative \u2014 false alarms are costly):
1192
+ - Default to "medium" confidence.
1193
+ - Use "high" ONLY when you can name a SPECIFIC criterion from the section that the diff and test output clearly met or clearly failed to meet, and quote or paraphrase it in the rationale.
1194
+ - Use "low" when the diff or test output is ambiguous, partial, or insufficient to judge.
1195
+ - When the change only PARTIALLY meets the criteria, do not exceed "medium" confidence.
1196
+ - Bias toward advisory caution: if unsure between two confidence levels, choose the lower one.
1197
+
1198
+ Rules:
1199
+ - The rationale MUST cite specific met or unmet criteria from the section.
1200
+ - "unmetCriteria" lists the section criteria the change failed to meet; it is empty when the verdict is SATISFIED.
1201
+ - Do NOT emit an "authority" field. Authority is computed downstream in TypeScript from (verdict, confidence) and must never come from you.
1202
+
1203
+ Return your judgment using the structured_output tool.`;
1204
+ var PROMPT_FIELD_MAX_CHARS = 12e3;
1205
+ var FENCE = "````";
1206
+ function clampField(text) {
1207
+ const trimmed = text.trim();
1208
+ if (trimmed.length <= PROMPT_FIELD_MAX_CHARS) return trimmed;
1209
+ const dropped = trimmed.length - PROMPT_FIELD_MAX_CHARS;
1210
+ return `${trimmed.slice(0, PROMPT_FIELD_MAX_CHARS)}
1211
+ \u2026 [truncated ${dropped} chars]`;
1212
+ }
1213
+ function buildUserPrompt2(section, diff, testOutput) {
1214
+ return [
1215
+ "## Spec Acceptance Criteria (judge against this section)",
1216
+ section.trim() || "(empty \u2014 treat as inconclusive)",
1217
+ "",
1218
+ "## Change Diff",
1219
+ `${FENCE}diff`,
1220
+ clampField(diff) || "(empty diff)",
1221
+ FENCE,
1222
+ "",
1223
+ "## Test Output",
1224
+ FENCE,
1225
+ clampField(testOutput) || "(no test output captured)",
1226
+ FENCE,
1227
+ "",
1228
+ "## Instructions",
1229
+ "Judge whether the diff satisfies the acceptance criteria above. Calibrate confidence conservatively per your system instructions. Cite specific criteria in the rationale."
1230
+ ].join("\n");
1231
+ }
1232
+
1233
+ // src/outcome-eval/section-resolver.ts
1234
+ var CHAIN = [
1235
+ { tag: "success-criteria", matches: (h) => h === "success criteria" },
1236
+ { tag: "user-visible-behavior", matches: (h) => h === "user visible behavior" },
1237
+ { tag: "overview", matches: (h) => h === "overview" }
1238
+ ];
1239
+ var HEADING_RE = /^(#{1,6})\s+(.*\S)\s*$/;
1240
+ var FENCE_RE = /^\s*(```|~~~)/;
1241
+ var normalizeHeading = (text) => text.toLowerCase().replace(/-/g, " ").replace(/\s+/g, " ").trim();
1242
+ var parseHeading = (line, index) => {
1243
+ const m = HEADING_RE.exec(line);
1244
+ if (!m || m[1] === void 0 || m[2] === void 0) return null;
1245
+ const normalized = normalizeHeading(m[2]);
1246
+ const entry = CHAIN.find((c) => c.matches(normalized));
1247
+ return { index, level: m[1].length, tag: entry ? entry.tag : null };
1248
+ };
1249
+ function resolveSection(markdown) {
1250
+ const lines = markdown.split(/\r?\n/);
1251
+ const headings = [];
1252
+ let inFence = false;
1253
+ lines.forEach((line, index) => {
1254
+ if (FENCE_RE.test(line)) {
1255
+ inFence = !inFence;
1256
+ return;
1257
+ }
1258
+ if (inFence) return;
1259
+ const heading = parseHeading(line, index);
1260
+ if (heading) headings.push(heading);
1261
+ });
1262
+ for (const { tag } of CHAIN) {
1263
+ const start = headings.find((h) => h.tag === tag);
1264
+ if (!start) continue;
1265
+ const next = headings.find((h) => h.index > start.index && h.level <= start.level);
1266
+ const endExclusive = next ? next.index : lines.length;
1267
+ const body = lines.slice(start.index + 1, endExclusive).join("\n").trim();
1268
+ return { judgedAgainst: tag, body };
1269
+ }
1270
+ return null;
1271
+ }
1272
+
1273
+ // src/outcome-eval/evaluator.ts
1274
+ import { readFile } from "fs/promises";
1275
+ import { randomUUID as randomUUID2 } from "crypto";
1276
+ var OutcomeEvaluator = class {
1277
+ provider;
1278
+ store;
1279
+ options;
1280
+ constructor(provider, store, options = {}) {
1281
+ this.provider = provider;
1282
+ this.store = store;
1283
+ this.options = options;
1284
+ }
1285
+ async evaluate(input) {
1286
+ let resolved;
1287
+ try {
1288
+ resolved = await this.resolveJudgmentSection(input);
1289
+ } catch {
1290
+ return this.finish(this.degradedVerdict("overview"), input);
1291
+ }
1292
+ if (resolved === null) {
1293
+ const verdict2 = this.buildVerdict(
1294
+ "INCONCLUSIVE",
1295
+ "low",
1296
+ "No judgable spec section found.",
1297
+ "overview",
1298
+ []
1299
+ );
1300
+ return this.finish(verdict2, input);
1301
+ }
1302
+ const verdict = await this.judge(resolved, input);
1303
+ return this.finish(verdict, input);
1304
+ }
1305
+ /**
1306
+ * Run the provider call and strict re-parse. ANY failure here — provider
1307
+ * rejection (rate limit/network), or a strict-parse rejection of a malformed
1308
+ * or authority-injected payload — degrades safely to INCONCLUSIVE/low/
1309
+ * advisory rather than throwing. This reconciles Criterion 3 (never block on
1310
+ * noise) with Criterion 4: an injected `authority` key is discarded by the
1311
+ * .strict() re-parse, and the degraded verdict's authority is DERIVED from
1312
+ * INCONCLUSIVE/low = advisory — so the LLM gains nothing by injecting it.
1313
+ */
1314
+ async judge(resolved, input) {
1315
+ try {
1316
+ const response = await this.provider.analyze({
1317
+ prompt: buildUserPrompt2(resolved.body, input.diff, input.testOutput),
1318
+ systemPrompt: OUTCOME_EVAL_SYSTEM_PROMPT,
1319
+ responseSchema: verdictSchema,
1320
+ ...this.options.model !== void 0 && { model: this.options.model }
1321
+ });
1322
+ const llm = verdictSchema.parse(response.result);
1323
+ return this.buildVerdict(
1324
+ llm.verdict,
1325
+ llm.confidence,
1326
+ llm.rationale,
1327
+ resolved.judgedAgainst,
1328
+ llm.unmetCriteria
1329
+ );
1330
+ } catch {
1331
+ return this.degradedVerdict(resolved.judgedAgainst);
1332
+ }
1333
+ }
1334
+ /**
1335
+ * Build the safe-degradation verdict. INCONCLUSIVE/low yields advisory
1336
+ * authority via deriveAuthority — never blocking. The rationale names only a
1337
+ * coarse reason category, never a stack trace or secret.
1338
+ */
1339
+ degradedVerdict(judgedAgainst) {
1340
+ return this.buildVerdict(
1341
+ "INCONCLUSIVE",
1342
+ "low",
1343
+ "Evaluation could not be completed; defaulting to an inconclusive, advisory verdict.",
1344
+ judgedAgainst,
1345
+ []
1346
+ );
1347
+ }
1348
+ /** Persist (Phase 4 seam) then return the verdict. */
1349
+ async finish(verdict, input) {
1350
+ await this.persistOutcome(verdict, input);
1351
+ return verdict;
1352
+ }
1353
+ async resolveJudgmentSection(input) {
1354
+ if (input.specSection !== void 0) {
1355
+ return input.specSection.trim() === "" ? null : { judgedAgainst: "success-criteria", body: input.specSection };
1356
+ }
1357
+ const markdown = await readFile(input.specPath, "utf8");
1358
+ return resolveSection(markdown);
1359
+ }
1360
+ buildVerdict(verdict, confidence, rationale, judgedAgainst, unmetCriteria) {
1361
+ return {
1362
+ verdict,
1363
+ confidence,
1364
+ rationale,
1365
+ judgedAgainst,
1366
+ unmetCriteria,
1367
+ authority: deriveAuthority(verdict, confidence)
1368
+ };
1369
+ }
1370
+ /**
1371
+ * Map an OutcomeVerdict + OutcomeEvalInput to the connector's ExecutionOutcome.
1372
+ * - result: SATISFIED -> 'success'; otherwise 'failure'. INCONCLUSIVE is
1373
+ * 'failure' for type-validity but omits agentPersona/affected systems so
1374
+ * the effectiveness scorer ignores it (plan D2).
1375
+ * - linkedSpecId: input.specPath (metadata only; no spec edge — plan D1).
1376
+ * - affectedSystemNodeIds: [] in v1 (not available from OutcomeEvalInput — D4).
1377
+ * - id: one node per EVALUATION. GraphStore.addNode upserts by id, so the id
1378
+ * carries a collision-free randomUUID() — two evaluate() calls in the same
1379
+ * millisecond can never overwrite each other (data-loss fix). specPath is
1380
+ * included for human readability only.
1381
+ * - taskType: OMITTED. The outcome-eval judge has no task categorization, and
1382
+ * asserting a false 'feature' would mislead specialization analytics (SUG-2).
1383
+ * - metadata: verdict-specific signal carried through the connector's
1384
+ * additive pass-through (verdict/confidence/judgedAgainst/source) so the
1385
+ * true 3-valued verdict is durable on the node (Truth 3).
1386
+ */
1387
+ toExecutionOutcome(verdict, input) {
1388
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1389
+ return {
1390
+ id: `outcome:outcome-eval:${input.specPath}:${randomUUID2()}`,
1391
+ issueId: "outcome-eval",
1392
+ identifier: `outcome-eval:${input.specPath}`,
1393
+ result: verdict.verdict === "SATISFIED" ? "success" : "failure",
1394
+ retryCount: 0,
1395
+ failureReasons: verdict.unmetCriteria,
1396
+ // 0 means "not applicable to outcome-eval" — the judge does not time work.
1397
+ durationMs: 0,
1398
+ linkedSpecId: input.specPath,
1399
+ affectedSystemNodeIds: [],
1400
+ timestamp,
1401
+ metadata: {
1402
+ verdict: verdict.verdict,
1403
+ confidence: verdict.confidence,
1404
+ judgedAgainst: verdict.judgedAgainst,
1405
+ source: "outcome-eval"
1406
+ }
1407
+ };
1408
+ }
1409
+ /**
1410
+ * Phase 4: writes exactly one execution_outcome node via
1411
+ * ExecutionOutcomeConnector. Degrade-safe (plan D3): a graph-write failure is
1412
+ * swallowed-and-logged, never thrown — the verdict is already computed before
1413
+ * this runs, so swallowing keeps evaluate() total. No secrets/stack frames in
1414
+ * the log message.
1415
+ */
1416
+ async persistOutcome(verdict, input) {
1417
+ try {
1418
+ const connector = new ExecutionOutcomeConnector(this.store);
1419
+ connector.ingest(this.toExecutionOutcome(verdict, input));
1420
+ } catch {
1421
+ console.warn("[outcome-eval] execution_outcome persistence failed; verdict unaffected.");
1422
+ }
1423
+ }
1424
+ };
1425
+
1048
1426
  // src/pipeline.ts
1049
1427
  var IntelligencePipeline = class {
1050
1428
  provider;
@@ -1521,16 +1899,21 @@ export {
1521
1899
  ExecutionOutcomeConnector,
1522
1900
  GraphValidator,
1523
1901
  IntelligencePipeline,
1902
+ OUTCOME_EVAL_SYSTEM_PROMPT,
1524
1903
  OpenAICompatibleAnalysisProvider,
1904
+ OutcomeEvaluator,
1525
1905
  PeslSimulator,
1526
1906
  buildSpecializationProfile,
1907
+ buildUserPrompt2 as buildUserPrompt,
1527
1908
  computeExpertiseLevel,
1528
1909
  computeHistoricalComplexity,
1529
1910
  computePersonaEffectiveness,
1530
1911
  computeSemanticComplexity,
1531
1912
  computeSpecialization,
1532
1913
  computeStructuralComplexity,
1914
+ createCanaryAdapter,
1533
1915
  decayWeight,
1916
+ deriveAuthority,
1534
1917
  detectBlindSpots,
1535
1918
  enrich,
1536
1919
  githubToRawWorkItem,
@@ -1540,6 +1923,7 @@ export {
1540
1923
  manualToRawWorkItem,
1541
1924
  recommendPersona,
1542
1925
  refreshProfiles,
1926
+ resolveSection,
1543
1927
  runGraphOnlyChecks,
1544
1928
  runLlmSimulation,
1545
1929
  saveProfiles,
@@ -1547,5 +1931,6 @@ export {
1547
1931
  scoreToConcernSignals,
1548
1932
  temporalSuccessRate,
1549
1933
  toRawWorkItem,
1934
+ verdictSchema,
1550
1935
  weightedRecommendPersona
1551
1936
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/intelligence",
3
- "version": "0.2.7",
3
+ "version": "0.3.1",
4
4
  "description": "Intelligence pipeline for spec enrichment, complexity modeling, and pre-execution simulation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -40,8 +40,11 @@
40
40
  "@anthropic-ai/sdk": "^0.95.1",
41
41
  "openai": "^6.0.0",
42
42
  "zod": "^3.25.76",
43
- "@harness-engineering/graph": "0.11.0",
44
- "@harness-engineering/types": "0.16.0"
43
+ "@harness-engineering/graph": "0.11.1",
44
+ "@harness-engineering/types": "0.16.1"
45
+ },
46
+ "optionalDependencies": {
47
+ "canary-test-cli": "^5.4.0"
45
48
  },
46
49
  "devDependencies": {
47
50
  "@types/node": "^22.19.15",