@harness-engineering/core 0.21.2 → 0.21.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.
package/dist/index.js CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  ARCHITECTURE_DESCRIPTOR: () => ARCHITECTURE_DESCRIPTOR,
36
36
  AdjustedForecastSchema: () => AdjustedForecastSchema,
37
37
  AgentActionEmitter: () => AgentActionEmitter,
38
+ AnthropicCacheAdapter: () => AnthropicCacheAdapter,
38
39
  ArchBaselineManager: () => ArchBaselineManager,
39
40
  ArchBaselineSchema: () => ArchBaselineSchema,
40
41
  ArchConfigSchema: () => ArchConfigSchema,
@@ -54,6 +55,7 @@ __export(index_exports, {
54
55
  CategorySnapshotSchema: () => CategorySnapshotSchema,
55
56
  ChecklistBuilder: () => ChecklistBuilder,
56
57
  CircularDepsCollector: () => CircularDepsCollector,
58
+ CompactionPipeline: () => CompactionPipeline,
57
59
  ComplexityCollector: () => ComplexityCollector,
58
60
  ConfidenceTierSchema: () => ConfidenceTierSchema,
59
61
  ConfirmationSchema: () => ConfirmationSchema,
@@ -68,6 +70,7 @@ __export(index_exports, {
68
70
  DEFAULT_STABILITY_THRESHOLDS: () => DEFAULT_STABILITY_THRESHOLDS,
69
71
  DEFAULT_STATE: () => DEFAULT_STATE,
70
72
  DEFAULT_STREAM_INDEX: () => DEFAULT_STREAM_INDEX,
73
+ DEFAULT_TOKEN_BUDGET: () => DEFAULT_TOKEN_BUDGET,
71
74
  DESTRUCTIVE_BASH: () => DESTRUCTIVE_BASH,
72
75
  DepDepthCollector: () => DepDepthCollector,
73
76
  DirectionSchema: () => DirectionSchema,
@@ -81,6 +84,7 @@ __export(index_exports, {
81
84
  ForbiddenImportCollector: () => ForbiddenImportCollector,
82
85
  GateConfigSchema: () => GateConfigSchema,
83
86
  GateResultSchema: () => GateResultSchema,
87
+ GeminiCacheAdapter: () => GeminiCacheAdapter,
84
88
  GitHubIssuesSyncAdapter: () => GitHubIssuesSyncAdapter,
85
89
  HandoffSchema: () => HandoffSchema,
86
90
  HarnessStateSchema: () => HarnessStateSchema,
@@ -95,6 +99,7 @@ __export(index_exports, {
95
99
  NoOpExecutor: () => NoOpExecutor,
96
100
  NoOpSink: () => NoOpSink,
97
101
  NoOpTelemetryAdapter: () => NoOpTelemetryAdapter,
102
+ OpenAICacheAdapter: () => OpenAICacheAdapter,
98
103
  PatternConfigSchema: () => PatternConfigSchema,
99
104
  PredictionEngine: () => PredictionEngine,
100
105
  PredictionOptionsSchema: () => PredictionOptionsSchema,
@@ -122,6 +127,7 @@ __export(index_exports, {
122
127
  StabilityForecastSchema: () => StabilityForecastSchema,
123
128
  StreamIndexSchema: () => StreamIndexSchema,
124
129
  StreamInfoSchema: () => StreamInfoSchema,
130
+ StructuralStrategy: () => StructuralStrategy,
125
131
  ThresholdConfigSchema: () => ThresholdConfigSchema,
126
132
  TimelineFileSchema: () => TimelineFileSchema,
127
133
  TimelineManager: () => TimelineManager,
@@ -129,13 +135,16 @@ __export(index_exports, {
129
135
  TransitionSchema: () => TransitionSchema,
130
136
  TrendLineSchema: () => TrendLineSchema,
131
137
  TrendResultSchema: () => TrendResultSchema,
138
+ TruncationStrategy: () => TruncationStrategy,
132
139
  TypeScriptParser: () => TypeScriptParser,
133
140
  VERSION: () => VERSION,
134
141
  ViolationSchema: () => ViolationSchema,
135
142
  addProvenance: () => addProvenance,
136
143
  agentConfigRules: () => agentConfigRules,
144
+ aggregateAdoptionByDay: () => aggregateByDay2,
137
145
  aggregateByDay: () => aggregateByDay,
138
146
  aggregateBySession: () => aggregateBySession,
147
+ aggregateBySkill: () => aggregateBySkill,
139
148
  analyzeDiff: () => analyzeDiff,
140
149
  analyzeLearningPatterns: () => analyzeLearningPatterns,
141
150
  appendFailure: () => appendFailure,
@@ -167,6 +176,7 @@ __export(index_exports, {
167
176
  clearFailuresCache: () => clearFailuresCache,
168
177
  clearLearningsCache: () => clearLearningsCache,
169
178
  clearTaint: () => clearTaint,
179
+ collectEvents: () => collectEvents,
170
180
  computeContentHash: () => computeContentHash,
171
181
  computeOverallSeverity: () => computeOverallSeverity,
172
182
  computeScanExitCode: () => computeScanExitCode,
@@ -206,6 +216,7 @@ __export(index_exports, {
206
216
  determineAssessment: () => determineAssessment,
207
217
  diff: () => diff,
208
218
  emitEvent: () => emitEvent,
219
+ estimateTokens: () => estimateTokens,
209
220
  executeWorkflow: () => executeWorkflow,
210
221
  expressRules: () => expressRules,
211
222
  extractBundle: () => extractBundle,
@@ -227,6 +238,7 @@ __export(index_exports, {
227
238
  getFeedbackConfig: () => getFeedbackConfig,
228
239
  getInjectionPatterns: () => getInjectionPatterns,
229
240
  getModelPrice: () => getModelPrice,
241
+ getOrCreateInstallId: () => getOrCreateInstallId,
230
242
  getOutline: () => getOutline,
231
243
  getParser: () => getParser,
232
244
  getPhaseCategories: () => getPhaseCategories,
@@ -279,8 +291,10 @@ __export(index_exports, {
279
291
  promoteSessionLearnings: () => promoteSessionLearnings,
280
292
  pruneLearnings: () => pruneLearnings,
281
293
  reactRules: () => reactRules,
294
+ readAdoptionRecords: () => readAdoptionRecords,
282
295
  readCheckState: () => readCheckState,
283
296
  readCostRecords: () => readCostRecords,
297
+ readIdentity: () => readIdentity,
284
298
  readLockfile: () => readLockfile,
285
299
  readSessionSection: () => readSessionSection,
286
300
  readSessionSections: () => readSessionSections,
@@ -291,11 +305,13 @@ __export(index_exports, {
291
305
  requestPeerReview: () => requestPeerReview,
292
306
  resetFeedbackConfig: () => resetFeedbackConfig,
293
307
  resetParserCache: () => resetParserCache,
308
+ resolveConsent: () => resolveConsent,
294
309
  resolveFileToLayer: () => resolveFileToLayer,
295
310
  resolveModelTier: () => resolveModelTier,
296
311
  resolveReverseStatus: () => resolveReverseStatus,
297
312
  resolveRuleSeverity: () => resolveRuleSeverity,
298
313
  resolveSessionDir: () => resolveSessionDir,
314
+ resolveStability: () => resolveStability,
299
315
  resolveStreamPath: () => resolveStreamPath,
300
316
  resolveThresholds: () => resolveThresholds3,
301
317
  runAll: () => runAll,
@@ -317,6 +333,8 @@ __export(index_exports, {
317
333
  scoreRoadmapCandidates: () => scoreRoadmapCandidates,
318
334
  searchSymbols: () => searchSymbols,
319
335
  secretRules: () => secretRules,
336
+ send: () => send,
337
+ serializeEnvelope: () => serializeEnvelope,
320
338
  serializeRoadmap: () => serializeRoadmap,
321
339
  setActiveStream: () => setActiveStream,
322
340
  sharpEdgesRules: () => sharpEdgesRules,
@@ -327,6 +345,7 @@ __export(index_exports, {
327
345
  syncRoadmap: () => syncRoadmap,
328
346
  syncToExternal: () => syncToExternal,
329
347
  tagUncitedFindings: () => tagUncitedFindings,
348
+ topSkills: () => topSkills,
330
349
  touchStream: () => touchStream,
331
350
  trackAction: () => trackAction,
332
351
  unfoldRange: () => unfoldRange,
@@ -372,17 +391,17 @@ var import_node_path = require("path");
372
391
  var import_glob = require("glob");
373
392
  var accessAsync = (0, import_util.promisify)(import_fs.access);
374
393
  var readFileAsync = (0, import_util.promisify)(import_fs.readFile);
375
- async function fileExists(path31) {
394
+ async function fileExists(path34) {
376
395
  try {
377
- await accessAsync(path31, import_fs.constants.F_OK);
396
+ await accessAsync(path34, import_fs.constants.F_OK);
378
397
  return true;
379
398
  } catch {
380
399
  return false;
381
400
  }
382
401
  }
383
- async function readFileContent(path31) {
402
+ async function readFileContent(path34) {
384
403
  try {
385
- const content = await readFileAsync(path31, "utf-8");
404
+ const content = await readFileAsync(path34, "utf-8");
386
405
  return (0, import_types.Ok)(content);
387
406
  } catch (error) {
388
407
  return (0, import_types.Err)(error);
@@ -433,15 +452,15 @@ function validateConfig(data, schema) {
433
452
  let message = "Configuration validation failed";
434
453
  const suggestions = [];
435
454
  if (firstError) {
436
- const path31 = firstError.path.join(".");
437
- const pathDisplay = path31 ? ` at "${path31}"` : "";
455
+ const path34 = firstError.path.join(".");
456
+ const pathDisplay = path34 ? ` at "${path34}"` : "";
438
457
  if (firstError.code === "invalid_type") {
439
458
  const received = firstError.received;
440
459
  const expected = firstError.expected;
441
460
  if (received === "undefined") {
442
461
  code = "MISSING_FIELD";
443
462
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
444
- suggestions.push(`Field "${path31}" is required and must be of type "${expected}"`);
463
+ suggestions.push(`Field "${path34}" is required and must be of type "${expected}"`);
445
464
  } else {
446
465
  code = "INVALID_TYPE";
447
466
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -660,27 +679,27 @@ function extractSections(content) {
660
679
  }
661
680
  return sections.map((section) => buildAgentMapSection(section, lines));
662
681
  }
663
- function isExternalLink(path31) {
664
- return path31.startsWith("http://") || path31.startsWith("https://") || path31.startsWith("#") || path31.startsWith("mailto:");
682
+ function isExternalLink(path34) {
683
+ return path34.startsWith("http://") || path34.startsWith("https://") || path34.startsWith("#") || path34.startsWith("mailto:");
665
684
  }
666
685
  function resolveLinkPath(linkPath, baseDir) {
667
686
  return linkPath.startsWith(".") ? (0, import_path.join)(baseDir, linkPath) : linkPath;
668
687
  }
669
- async function validateAgentsMap(path31 = "./AGENTS.md") {
670
- const contentResult = await readFileContent(path31);
688
+ async function validateAgentsMap(path34 = "./AGENTS.md") {
689
+ const contentResult = await readFileContent(path34);
671
690
  if (!contentResult.ok) {
672
691
  return (0, import_types.Err)(
673
692
  createError(
674
693
  "PARSE_ERROR",
675
694
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
676
- { path: path31 },
695
+ { path: path34 },
677
696
  ["Ensure the file exists", "Check file permissions"]
678
697
  )
679
698
  );
680
699
  }
681
700
  const content = contentResult.value;
682
701
  const sections = extractSections(content);
683
- const baseDir = (0, import_path.dirname)(path31);
702
+ const baseDir = (0, import_path.dirname)(path34);
684
703
  const sectionTitles = sections.map((s) => s.title);
685
704
  const missingSections = REQUIRED_SECTIONS.filter(
686
705
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -821,8 +840,8 @@ async function checkDocCoverage(domain, options = {}) {
821
840
 
822
841
  // src/context/knowledge-map.ts
823
842
  var import_path3 = require("path");
824
- function suggestFix(path31, existingFiles) {
825
- const targetName = (0, import_path3.basename)(path31).toLowerCase();
843
+ function suggestFix(path34, existingFiles) {
844
+ const targetName = (0, import_path3.basename)(path34).toLowerCase();
826
845
  const similar = existingFiles.find((file) => {
827
846
  const fileName = (0, import_path3.basename)(file).toLowerCase();
828
847
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -830,7 +849,7 @@ function suggestFix(path31, existingFiles) {
830
849
  if (similar) {
831
850
  return `Did you mean "${similar}"?`;
832
851
  }
833
- return `Create the file "${path31}" or remove the link`;
852
+ return `Create the file "${path34}" or remove the link`;
834
853
  }
835
854
  async function validateKnowledgeMap(rootDir = process.cwd()) {
836
855
  const agentsPath = (0, import_path3.join)(rootDir, "AGENTS.md");
@@ -1434,8 +1453,8 @@ function createBoundaryValidator(schema, name) {
1434
1453
  return (0, import_types.Ok)(result.data);
1435
1454
  }
1436
1455
  const suggestions = result.error.issues.map((issue) => {
1437
- const path31 = issue.path.join(".");
1438
- return path31 ? `${path31}: ${issue.message}` : issue.message;
1456
+ const path34 = issue.path.join(".");
1457
+ return path34 ? `${path34}: ${issue.message}` : issue.message;
1439
1458
  });
1440
1459
  return (0, import_types.Err)(
1441
1460
  createError(
@@ -2069,11 +2088,11 @@ function processExportListSpecifiers(exportDecl, exports2) {
2069
2088
  var TypeScriptParser = class {
2070
2089
  name = "typescript";
2071
2090
  extensions = [".ts", ".tsx", ".mts", ".cts"];
2072
- async parseFile(path31) {
2073
- const contentResult = await readFileContent(path31);
2091
+ async parseFile(path34) {
2092
+ const contentResult = await readFileContent(path34);
2074
2093
  if (!contentResult.ok) {
2075
2094
  return (0, import_types.Err)(
2076
- createParseError("NOT_FOUND", `File not found: ${path31}`, { path: path31 }, [
2095
+ createParseError("NOT_FOUND", `File not found: ${path34}`, { path: path34 }, [
2077
2096
  "Check that the file exists",
2078
2097
  "Verify the path is correct"
2079
2098
  ])
@@ -2083,7 +2102,7 @@ var TypeScriptParser = class {
2083
2102
  const ast = (0, import_typescript_estree.parse)(contentResult.value, {
2084
2103
  loc: true,
2085
2104
  range: true,
2086
- jsx: path31.endsWith(".tsx"),
2105
+ jsx: path34.endsWith(".tsx"),
2087
2106
  errorOnUnknownASTType: false
2088
2107
  });
2089
2108
  return (0, import_types.Ok)({
@@ -2094,7 +2113,7 @@ var TypeScriptParser = class {
2094
2113
  } catch (e) {
2095
2114
  const error = e;
2096
2115
  return (0, import_types.Err)(
2097
- createParseError("SYNTAX_ERROR", `Failed to parse ${path31}: ${error.message}`, { path: path31 }, [
2116
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path34}: ${error.message}`, { path: path34 }, [
2098
2117
  "Check for syntax errors in the file",
2099
2118
  "Ensure valid TypeScript syntax"
2100
2119
  ])
@@ -2279,22 +2298,22 @@ function extractInlineRefs(content) {
2279
2298
  }
2280
2299
  return refs;
2281
2300
  }
2282
- async function parseDocumentationFile(path31) {
2283
- const contentResult = await readFileContent(path31);
2301
+ async function parseDocumentationFile(path34) {
2302
+ const contentResult = await readFileContent(path34);
2284
2303
  if (!contentResult.ok) {
2285
2304
  return (0, import_types.Err)(
2286
2305
  createEntropyError(
2287
2306
  "PARSE_ERROR",
2288
- `Failed to read documentation file: ${path31}`,
2289
- { file: path31 },
2307
+ `Failed to read documentation file: ${path34}`,
2308
+ { file: path34 },
2290
2309
  ["Check that the file exists"]
2291
2310
  )
2292
2311
  );
2293
2312
  }
2294
2313
  const content = contentResult.value;
2295
- const type = path31.endsWith(".md") ? "markdown" : "text";
2314
+ const type = path34.endsWith(".md") ? "markdown" : "text";
2296
2315
  return (0, import_types.Ok)({
2297
- path: path31,
2316
+ path: path34,
2298
2317
  type,
2299
2318
  content,
2300
2319
  codeBlocks: extractCodeBlocks(content),
@@ -5074,12 +5093,12 @@ function parseDiffHeader(part) {
5074
5093
  return headerMatch[2];
5075
5094
  }
5076
5095
  function parseDiffPart(part) {
5077
- const path31 = parseDiffHeader(part);
5078
- if (!path31) return null;
5096
+ const path34 = parseDiffHeader(part);
5097
+ if (!path34) return null;
5079
5098
  const additionRegex = /^\+(?!\+\+)/gm;
5080
5099
  const deletionRegex = /^-(?!--)/gm;
5081
5100
  return {
5082
- path: path31,
5101
+ path: path34,
5083
5102
  status: detectFileStatus(part),
5084
5103
  additions: (part.match(additionRegex) || []).length,
5085
5104
  deletions: (part.match(deletionRegex) || []).length
@@ -8536,6 +8555,35 @@ async function saveState(projectPath, state, stream, session) {
8536
8555
  var fs11 = __toESM(require("fs"));
8537
8556
  var path8 = __toESM(require("path"));
8538
8557
  var crypto2 = __toESM(require("crypto"));
8558
+
8559
+ // src/compaction/envelope.ts
8560
+ function estimateTokens(content) {
8561
+ return Math.ceil(content.length / 4);
8562
+ }
8563
+ function serializeEnvelope(envelope) {
8564
+ const { meta, sections } = envelope;
8565
+ const strategyLabel = meta.strategy.length > 0 ? meta.strategy.join("+") : "none";
8566
+ let cacheLabel = "";
8567
+ if (meta.cached) {
8568
+ if (meta.cacheReadTokens != null && meta.cacheInputTokens != null && meta.cacheInputTokens > 0) {
8569
+ const hitPct = Math.round(meta.cacheReadTokens / meta.cacheInputTokens * 100);
8570
+ const readFormatted = meta.cacheReadTokens >= 1e3 ? (meta.cacheReadTokens / 1e3).toFixed(1) + "K" : String(meta.cacheReadTokens);
8571
+ cacheLabel = ` [cached | cache: ${readFormatted} read, ${hitPct}% hit]`;
8572
+ } else {
8573
+ cacheLabel = " [cached]";
8574
+ }
8575
+ }
8576
+ const header = `<!-- packed: ${strategyLabel} | ${meta.originalTokenEstimate}\u2192${meta.compactedTokenEstimate} tokens (-${meta.reductionPct}%)${cacheLabel} -->`;
8577
+ if (sections.length === 0) {
8578
+ return header;
8579
+ }
8580
+ const body = sections.map((section) => `### [${section.source}]
8581
+ ${section.content}`).join("\n\n");
8582
+ return `${header}
8583
+ ${body}`;
8584
+ }
8585
+
8586
+ // src/state/learnings-content.ts
8539
8587
  function parseFrontmatter2(line) {
8540
8588
  const match = line.match(/^<!--\s+hash:([a-f0-9]+)(?:\s+tags:([^\s]+))?\s+-->/);
8541
8589
  if (!match) return null;
@@ -8639,9 +8687,6 @@ function analyzeLearningPatterns(entries) {
8639
8687
  }
8640
8688
  return patterns.sort((a, b) => b.count - a.count);
8641
8689
  }
8642
- function estimateTokens(text) {
8643
- return Math.ceil(text.length / 4);
8644
- }
8645
8690
  function scoreRelevance(entry, intent) {
8646
8691
  if (!intent || intent.trim() === "") return 0;
8647
8692
  const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
@@ -14602,9 +14647,9 @@ async function resolveWasmPath(grammarName) {
14602
14647
  const { createRequire } = await import("module");
14603
14648
  const require2 = createRequire(import_meta.url ?? __filename);
14604
14649
  const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
14605
- const path31 = await import("path");
14606
- const pkgDir = path31.dirname(pkgPath);
14607
- return path31.join(pkgDir, "out", `${grammarName}.wasm`);
14650
+ const path34 = await import("path");
14651
+ const pkgDir = path34.dirname(pkgPath);
14652
+ return path34.join(pkgDir, "out", `${grammarName}.wasm`);
14608
14653
  }
14609
14654
  async function loadLanguage(lang) {
14610
14655
  const grammarName = GRAMMAR_MAP[lang];
@@ -15484,14 +15529,458 @@ function parseCCRecords() {
15484
15529
  return records;
15485
15530
  }
15486
15531
 
15487
- // src/index.ts
15488
- var VERSION = "0.21.1";
15532
+ // src/adoption/reader.ts
15533
+ var fs32 = __toESM(require("fs"));
15534
+ var path31 = __toESM(require("path"));
15535
+ function parseLine2(line, lineNumber) {
15536
+ try {
15537
+ const parsed = JSON.parse(line);
15538
+ if (typeof parsed.skill !== "string" || typeof parsed.startedAt !== "string" || typeof parsed.duration !== "number" || typeof parsed.outcome !== "string" || !Array.isArray(parsed.phasesReached)) {
15539
+ process.stderr.write(
15540
+ `[harness adoption] Skipping malformed JSONL line ${lineNumber}: missing required fields
15541
+ `
15542
+ );
15543
+ return null;
15544
+ }
15545
+ return parsed;
15546
+ } catch {
15547
+ process.stderr.write(`[harness adoption] Skipping malformed JSONL line ${lineNumber}
15548
+ `);
15549
+ return null;
15550
+ }
15551
+ }
15552
+ function readAdoptionRecords(projectRoot) {
15553
+ const adoptionFile = path31.join(projectRoot, ".harness", "metrics", "adoption.jsonl");
15554
+ let raw;
15555
+ try {
15556
+ raw = fs32.readFileSync(adoptionFile, "utf-8");
15557
+ } catch {
15558
+ return [];
15559
+ }
15560
+ const records = [];
15561
+ const lines = raw.split("\n");
15562
+ for (let i = 0; i < lines.length; i++) {
15563
+ const line = lines[i]?.trim();
15564
+ if (!line) continue;
15565
+ const record = parseLine2(line, i + 1);
15566
+ if (record) {
15567
+ records.push(record);
15568
+ }
15569
+ }
15570
+ return records;
15571
+ }
15572
+
15573
+ // src/adoption/aggregator.ts
15574
+ function aggregateBySkill(records) {
15575
+ if (records.length === 0) return [];
15576
+ const skillMap = /* @__PURE__ */ new Map();
15577
+ for (const record of records) {
15578
+ if (!skillMap.has(record.skill)) {
15579
+ const entry = { records: [] };
15580
+ if (record.tier != null) entry.tier = record.tier;
15581
+ skillMap.set(record.skill, entry);
15582
+ }
15583
+ skillMap.get(record.skill).records.push(record);
15584
+ }
15585
+ const results = [];
15586
+ for (const [skill, bucket] of skillMap) {
15587
+ const invocations = bucket.records.length;
15588
+ const completedCount = bucket.records.filter((r) => r.outcome === "completed").length;
15589
+ const totalDuration = bucket.records.reduce((sum, r) => sum + r.duration, 0);
15590
+ const timestamps = bucket.records.map((r) => r.startedAt).sort();
15591
+ const summary = {
15592
+ skill,
15593
+ invocations,
15594
+ successRate: completedCount / invocations,
15595
+ avgDuration: totalDuration / invocations,
15596
+ lastUsed: timestamps[timestamps.length - 1]
15597
+ };
15598
+ if (bucket.tier != null) summary.tier = bucket.tier;
15599
+ results.push(summary);
15600
+ }
15601
+ results.sort((a, b) => b.invocations - a.invocations);
15602
+ return results;
15603
+ }
15604
+ function aggregateByDay2(records) {
15605
+ if (records.length === 0) return [];
15606
+ const dayMap = /* @__PURE__ */ new Map();
15607
+ for (const record of records) {
15608
+ const date = record.startedAt.slice(0, 10);
15609
+ if (!dayMap.has(date)) {
15610
+ dayMap.set(date, { invocations: 0, skills: /* @__PURE__ */ new Set() });
15611
+ }
15612
+ const bucket = dayMap.get(date);
15613
+ bucket.invocations++;
15614
+ bucket.skills.add(record.skill);
15615
+ }
15616
+ const results = [];
15617
+ for (const [date, bucket] of dayMap) {
15618
+ results.push({
15619
+ date,
15620
+ invocations: bucket.invocations,
15621
+ uniqueSkills: bucket.skills.size
15622
+ });
15623
+ }
15624
+ results.sort((a, b) => b.date.localeCompare(a.date));
15625
+ return results;
15626
+ }
15627
+ function topSkills(records, n) {
15628
+ return aggregateBySkill(records).slice(0, n);
15629
+ }
15630
+
15631
+ // src/compaction/strategies/structural.ts
15632
+ function isEmptyObject(v) {
15633
+ return typeof v === "object" && v !== null && !Array.isArray(v) && Object.keys(v).length === 0;
15634
+ }
15635
+ function isRetainable(v) {
15636
+ return v !== void 0 && v !== "" && v !== null && !isEmptyObject(v);
15637
+ }
15638
+ function cleanArray(value) {
15639
+ const cleaned = value.map(cleanValue).filter(isRetainable);
15640
+ if (cleaned.length === 0) return void 0;
15641
+ if (cleaned.length === 1) return cleaned[0];
15642
+ return cleaned;
15643
+ }
15644
+ function cleanRecord(value) {
15645
+ const cleaned = {};
15646
+ for (const [k, v] of Object.entries(value)) {
15647
+ const result = cleanValue(v);
15648
+ if (isRetainable(result)) {
15649
+ cleaned[k] = result;
15650
+ }
15651
+ }
15652
+ if (Object.keys(cleaned).length === 0) return void 0;
15653
+ return cleaned;
15654
+ }
15655
+ function cleanValue(value) {
15656
+ if (value === null || value === void 0) return void 0;
15657
+ if (typeof value === "string") return value.replace(/\s+/g, " ").trim();
15658
+ if (Array.isArray(value)) return cleanArray(value);
15659
+ if (typeof value === "object") return cleanRecord(value);
15660
+ return value;
15661
+ }
15662
+ var StructuralStrategy = class {
15663
+ name = "structural";
15664
+ lossy = false;
15665
+ apply(content, _budget) {
15666
+ let parsed;
15667
+ try {
15668
+ parsed = JSON.parse(content);
15669
+ } catch {
15670
+ return content;
15671
+ }
15672
+ const cleaned = cleanValue(parsed);
15673
+ return JSON.stringify(cleaned) ?? "";
15674
+ }
15675
+ };
15676
+
15677
+ // src/compaction/strategies/truncation.ts
15678
+ var DEFAULT_TOKEN_BUDGET = 4e3;
15679
+ var CHARS_PER_TOKEN = 4;
15680
+ var TRUNCATION_MARKER = "\n[truncated \u2014 prioritized truncation applied]";
15681
+ function lineScore(line) {
15682
+ let score = 0;
15683
+ if (/\/[\w./-]/.test(line)) score += 40;
15684
+ if (/error|Error|ERROR|fail|FAIL|status/i.test(line)) score += 35;
15685
+ if (/\b[A-Z][a-z]+[A-Z]/.test(line) || /\b[a-z]+[A-Z]/.test(line)) score += 20;
15686
+ if (line.trim().length < 40) score += 10;
15687
+ return score;
15688
+ }
15689
+ function selectLines(lines, charBudget) {
15690
+ const scored = lines.map((line, idx) => ({ line, idx, score: lineScore(line) }));
15691
+ scored.sort((a, b) => b.score - a.score || a.idx - b.idx);
15692
+ const kept = [];
15693
+ let used = 0;
15694
+ for (const item of scored) {
15695
+ const lineLen = item.line.length + 1;
15696
+ if (used + lineLen > charBudget) continue;
15697
+ kept.push({ line: item.line, idx: item.idx });
15698
+ used += lineLen;
15699
+ }
15700
+ kept.sort((a, b) => a.idx - b.idx);
15701
+ return kept;
15702
+ }
15703
+ var TruncationStrategy = class {
15704
+ name = "truncate";
15705
+ lossy = false;
15706
+ // deliberate: spec Decision 2 — truncation is classified lossless at the pipeline level
15707
+ apply(content, budget = DEFAULT_TOKEN_BUDGET) {
15708
+ if (!content) return content;
15709
+ const charBudget = budget * CHARS_PER_TOKEN;
15710
+ if (content.length <= charBudget) return content;
15711
+ const lines = content.split("\n");
15712
+ const available = charBudget - TRUNCATION_MARKER.length;
15713
+ const kept = available > 0 ? selectLines(lines, available) : [{ line: (lines[0] ?? "").slice(0, charBudget), idx: 0 }];
15714
+ return kept.map((k) => k.line).join("\n") + TRUNCATION_MARKER;
15715
+ }
15716
+ };
15717
+
15718
+ // src/compaction/pipeline.ts
15719
+ var CompactionPipeline = class {
15720
+ strategies;
15721
+ constructor(strategies) {
15722
+ this.strategies = strategies;
15723
+ }
15724
+ /** The ordered list of strategy names in this pipeline. */
15725
+ get strategyNames() {
15726
+ return this.strategies.map((s) => s.name);
15727
+ }
15728
+ /**
15729
+ * Apply all strategies in order.
15730
+ * @param content — input string
15731
+ * @param budget — optional token budget forwarded to each strategy
15732
+ */
15733
+ apply(content, budget) {
15734
+ return this.strategies.reduce((current, strategy) => {
15735
+ return strategy.apply(current, budget);
15736
+ }, content);
15737
+ }
15738
+ };
15739
+
15740
+ // src/caching/stability.ts
15741
+ var import_graph2 = require("@harness-engineering/graph");
15742
+ var STABILITY_LOOKUP = {};
15743
+ for (const [key, tier] of Object.entries(import_graph2.NODE_STABILITY)) {
15744
+ STABILITY_LOOKUP[key] = tier;
15745
+ STABILITY_LOOKUP[key.toLowerCase()] = tier;
15746
+ }
15747
+ STABILITY_LOOKUP["packed_summary"] = "session";
15748
+ STABILITY_LOOKUP["skill"] = "static";
15749
+ function resolveStability(contentType) {
15750
+ return STABILITY_LOOKUP[contentType] ?? "ephemeral";
15751
+ }
15752
+
15753
+ // src/caching/adapters/anthropic.ts
15754
+ var TIER_ORDER = {
15755
+ static: 0,
15756
+ session: 1,
15757
+ ephemeral: 2
15758
+ };
15759
+ var AnthropicCacheAdapter = class {
15760
+ provider = "claude";
15761
+ wrapSystemBlock(content, stability) {
15762
+ if (stability === "ephemeral") {
15763
+ return { type: "text", text: content };
15764
+ }
15765
+ const ttl = stability === "static" ? "1h" : void 0;
15766
+ return {
15767
+ type: "text",
15768
+ text: content,
15769
+ cache_control: {
15770
+ type: "ephemeral",
15771
+ ...ttl !== void 0 && { ttl }
15772
+ }
15773
+ };
15774
+ }
15775
+ wrapTools(tools, stability) {
15776
+ if (tools.length === 0 || stability === "ephemeral") {
15777
+ return { tools: tools.map((t) => ({ ...t })) };
15778
+ }
15779
+ const wrapped = tools.map((t) => ({ ...t }));
15780
+ const last = wrapped[wrapped.length - 1];
15781
+ if (last) {
15782
+ last.cache_control = { type: "ephemeral" };
15783
+ }
15784
+ return { tools: wrapped };
15785
+ }
15786
+ orderContent(blocks) {
15787
+ return [...blocks].sort((a, b) => TIER_ORDER[a.stability] - TIER_ORDER[b.stability]);
15788
+ }
15789
+ parseCacheUsage(response) {
15790
+ const resp = response;
15791
+ const usage = resp?.usage;
15792
+ return {
15793
+ cacheCreationTokens: usage?.cache_creation_input_tokens ?? 0,
15794
+ cacheReadTokens: usage?.cache_read_input_tokens ?? 0
15795
+ };
15796
+ }
15797
+ };
15798
+
15799
+ // src/caching/adapters/openai.ts
15800
+ var TIER_ORDER2 = {
15801
+ static: 0,
15802
+ session: 1,
15803
+ ephemeral: 2
15804
+ };
15805
+ var OpenAICacheAdapter = class {
15806
+ provider = "openai";
15807
+ wrapSystemBlock(content, _stability) {
15808
+ return { type: "text", text: content };
15809
+ }
15810
+ wrapTools(tools, _stability) {
15811
+ return { tools: tools.map((t) => ({ ...t })) };
15812
+ }
15813
+ orderContent(blocks) {
15814
+ return [...blocks].sort((a, b) => TIER_ORDER2[a.stability] - TIER_ORDER2[b.stability]);
15815
+ }
15816
+ parseCacheUsage(response) {
15817
+ const resp = response;
15818
+ const usage = resp?.usage;
15819
+ const details = usage?.prompt_tokens_details;
15820
+ return {
15821
+ cacheCreationTokens: 0,
15822
+ cacheReadTokens: details?.cached_tokens ?? 0
15823
+ };
15824
+ }
15825
+ };
15826
+
15827
+ // src/caching/adapters/gemini.ts
15828
+ var TIER_ORDER3 = {
15829
+ static: 0,
15830
+ session: 1,
15831
+ ephemeral: 2
15832
+ };
15833
+ var CACHED_CONTENT_MARKER = "cachedContents:pending";
15834
+ var GeminiCacheAdapter = class {
15835
+ provider = "gemini";
15836
+ wrapSystemBlock(content, stability) {
15837
+ if (stability === "static") {
15838
+ return {
15839
+ type: "text",
15840
+ text: content,
15841
+ cachedContentRef: CACHED_CONTENT_MARKER
15842
+ };
15843
+ }
15844
+ return { type: "text", text: content };
15845
+ }
15846
+ wrapTools(tools, _stability) {
15847
+ return { tools: tools.map((t) => ({ ...t })) };
15848
+ }
15849
+ orderContent(blocks) {
15850
+ return [...blocks].sort((a, b) => TIER_ORDER3[a.stability] - TIER_ORDER3[b.stability]);
15851
+ }
15852
+ parseCacheUsage(response) {
15853
+ const resp = response;
15854
+ const metadata = resp?.usageMetadata;
15855
+ return {
15856
+ cacheCreationTokens: 0,
15857
+ cacheReadTokens: metadata?.cachedContentTokenCount ?? 0
15858
+ };
15859
+ }
15860
+ };
15861
+
15862
+ // src/telemetry/consent.ts
15863
+ var fs34 = __toESM(require("fs"));
15864
+ var path33 = __toESM(require("path"));
15865
+
15866
+ // src/telemetry/install-id.ts
15867
+ var fs33 = __toESM(require("fs"));
15868
+ var path32 = __toESM(require("path"));
15869
+ var crypto4 = __toESM(require("crypto"));
15870
+ function getOrCreateInstallId(projectRoot) {
15871
+ const harnessDir = path32.join(projectRoot, ".harness");
15872
+ const installIdFile = path32.join(harnessDir, ".install-id");
15873
+ const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
15874
+ try {
15875
+ const existing = fs33.readFileSync(installIdFile, "utf-8").trim();
15876
+ if (UUID_V4_RE.test(existing)) {
15877
+ return existing;
15878
+ }
15879
+ } catch {
15880
+ }
15881
+ const id = crypto4.randomUUID();
15882
+ fs33.mkdirSync(harnessDir, { recursive: true });
15883
+ fs33.writeFileSync(installIdFile, id, { encoding: "utf-8", mode: 384 });
15884
+ return id;
15885
+ }
15886
+
15887
+ // src/telemetry/consent.ts
15888
+ function readIdentity(projectRoot) {
15889
+ const filePath = path33.join(projectRoot, ".harness", "telemetry.json");
15890
+ try {
15891
+ const raw = fs34.readFileSync(filePath, "utf-8");
15892
+ const parsed = JSON.parse(raw);
15893
+ if (parsed && typeof parsed === "object" && parsed.identity) {
15894
+ const { project, team, alias } = parsed.identity;
15895
+ const identity = {};
15896
+ if (typeof project === "string") identity.project = project;
15897
+ if (typeof team === "string") identity.team = team;
15898
+ if (typeof alias === "string") identity.alias = alias;
15899
+ return identity;
15900
+ }
15901
+ return {};
15902
+ } catch {
15903
+ return {};
15904
+ }
15905
+ }
15906
+ function resolveConsent(projectRoot, config) {
15907
+ if (process.env.DO_NOT_TRACK === "1") return { allowed: false };
15908
+ if (process.env.HARNESS_TELEMETRY_OPTOUT === "1") return { allowed: false };
15909
+ const enabled = config?.enabled ?? true;
15910
+ if (!enabled) return { allowed: false };
15911
+ const installId = getOrCreateInstallId(projectRoot);
15912
+ const identity = readIdentity(projectRoot);
15913
+ return { allowed: true, installId, identity };
15914
+ }
15915
+
15916
+ // src/version.ts
15917
+ var VERSION = "0.21.3";
15918
+
15919
+ // src/telemetry/collector.ts
15920
+ function mapOutcome(outcome) {
15921
+ return outcome === "completed" ? "success" : "failure";
15922
+ }
15923
+ function collectEvents(projectRoot, consent) {
15924
+ const records = readAdoptionRecords(projectRoot);
15925
+ if (records.length === 0) return [];
15926
+ const { installId, identity } = consent;
15927
+ const distinctId = identity.alias ?? installId;
15928
+ return records.map(
15929
+ (record) => ({
15930
+ event: "skill_invocation",
15931
+ distinctId,
15932
+ timestamp: record.startedAt,
15933
+ properties: {
15934
+ installId,
15935
+ os: process.platform,
15936
+ nodeVersion: process.version,
15937
+ harnessVersion: VERSION,
15938
+ skillName: record.skill,
15939
+ duration: record.duration,
15940
+ outcome: mapOutcome(record.outcome),
15941
+ phasesReached: record.phasesReached,
15942
+ ...identity.project ? { project: identity.project } : {},
15943
+ ...identity.team ? { team: identity.team } : {}
15944
+ }
15945
+ })
15946
+ );
15947
+ }
15948
+
15949
+ // src/telemetry/transport.ts
15950
+ var POSTHOG_BATCH_URL = "https://app.posthog.com/batch";
15951
+ var MAX_ATTEMPTS = 3;
15952
+ var TIMEOUT_MS = 5e3;
15953
+ function sleep2(ms) {
15954
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
15955
+ }
15956
+ async function send(events, apiKey) {
15957
+ if (events.length === 0) return;
15958
+ const payload = { api_key: apiKey, batch: events };
15959
+ const body = JSON.stringify(payload);
15960
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
15961
+ try {
15962
+ const res = await fetch(POSTHOG_BATCH_URL, {
15963
+ method: "POST",
15964
+ headers: { "Content-Type": "application/json" },
15965
+ body,
15966
+ signal: AbortSignal.timeout(TIMEOUT_MS)
15967
+ });
15968
+ if (res.ok) return;
15969
+ if (res.status < 500) return;
15970
+ } catch {
15971
+ }
15972
+ if (attempt < MAX_ATTEMPTS - 1) {
15973
+ await sleep2(1e3 * (attempt + 1));
15974
+ }
15975
+ }
15976
+ }
15489
15977
  // Annotate the CommonJS export names for ESM import in node:
15490
15978
  0 && (module.exports = {
15491
15979
  AGENT_DESCRIPTORS,
15492
15980
  ARCHITECTURE_DESCRIPTOR,
15493
15981
  AdjustedForecastSchema,
15494
15982
  AgentActionEmitter,
15983
+ AnthropicCacheAdapter,
15495
15984
  ArchBaselineManager,
15496
15985
  ArchBaselineSchema,
15497
15986
  ArchConfigSchema,
@@ -15511,6 +16000,7 @@ var VERSION = "0.21.1";
15511
16000
  CategorySnapshotSchema,
15512
16001
  ChecklistBuilder,
15513
16002
  CircularDepsCollector,
16003
+ CompactionPipeline,
15514
16004
  ComplexityCollector,
15515
16005
  ConfidenceTierSchema,
15516
16006
  ConfirmationSchema,
@@ -15525,6 +16015,7 @@ var VERSION = "0.21.1";
15525
16015
  DEFAULT_STABILITY_THRESHOLDS,
15526
16016
  DEFAULT_STATE,
15527
16017
  DEFAULT_STREAM_INDEX,
16018
+ DEFAULT_TOKEN_BUDGET,
15528
16019
  DESTRUCTIVE_BASH,
15529
16020
  DepDepthCollector,
15530
16021
  DirectionSchema,
@@ -15538,6 +16029,7 @@ var VERSION = "0.21.1";
15538
16029
  ForbiddenImportCollector,
15539
16030
  GateConfigSchema,
15540
16031
  GateResultSchema,
16032
+ GeminiCacheAdapter,
15541
16033
  GitHubIssuesSyncAdapter,
15542
16034
  HandoffSchema,
15543
16035
  HarnessStateSchema,
@@ -15552,6 +16044,7 @@ var VERSION = "0.21.1";
15552
16044
  NoOpExecutor,
15553
16045
  NoOpSink,
15554
16046
  NoOpTelemetryAdapter,
16047
+ OpenAICacheAdapter,
15555
16048
  PatternConfigSchema,
15556
16049
  PredictionEngine,
15557
16050
  PredictionOptionsSchema,
@@ -15579,6 +16072,7 @@ var VERSION = "0.21.1";
15579
16072
  StabilityForecastSchema,
15580
16073
  StreamIndexSchema,
15581
16074
  StreamInfoSchema,
16075
+ StructuralStrategy,
15582
16076
  ThresholdConfigSchema,
15583
16077
  TimelineFileSchema,
15584
16078
  TimelineManager,
@@ -15586,13 +16080,16 @@ var VERSION = "0.21.1";
15586
16080
  TransitionSchema,
15587
16081
  TrendLineSchema,
15588
16082
  TrendResultSchema,
16083
+ TruncationStrategy,
15589
16084
  TypeScriptParser,
15590
16085
  VERSION,
15591
16086
  ViolationSchema,
15592
16087
  addProvenance,
15593
16088
  agentConfigRules,
16089
+ aggregateAdoptionByDay,
15594
16090
  aggregateByDay,
15595
16091
  aggregateBySession,
16092
+ aggregateBySkill,
15596
16093
  analyzeDiff,
15597
16094
  analyzeLearningPatterns,
15598
16095
  appendFailure,
@@ -15624,6 +16121,7 @@ var VERSION = "0.21.1";
15624
16121
  clearFailuresCache,
15625
16122
  clearLearningsCache,
15626
16123
  clearTaint,
16124
+ collectEvents,
15627
16125
  computeContentHash,
15628
16126
  computeOverallSeverity,
15629
16127
  computeScanExitCode,
@@ -15663,6 +16161,7 @@ var VERSION = "0.21.1";
15663
16161
  determineAssessment,
15664
16162
  diff,
15665
16163
  emitEvent,
16164
+ estimateTokens,
15666
16165
  executeWorkflow,
15667
16166
  expressRules,
15668
16167
  extractBundle,
@@ -15684,6 +16183,7 @@ var VERSION = "0.21.1";
15684
16183
  getFeedbackConfig,
15685
16184
  getInjectionPatterns,
15686
16185
  getModelPrice,
16186
+ getOrCreateInstallId,
15687
16187
  getOutline,
15688
16188
  getParser,
15689
16189
  getPhaseCategories,
@@ -15736,8 +16236,10 @@ var VERSION = "0.21.1";
15736
16236
  promoteSessionLearnings,
15737
16237
  pruneLearnings,
15738
16238
  reactRules,
16239
+ readAdoptionRecords,
15739
16240
  readCheckState,
15740
16241
  readCostRecords,
16242
+ readIdentity,
15741
16243
  readLockfile,
15742
16244
  readSessionSection,
15743
16245
  readSessionSections,
@@ -15748,11 +16250,13 @@ var VERSION = "0.21.1";
15748
16250
  requestPeerReview,
15749
16251
  resetFeedbackConfig,
15750
16252
  resetParserCache,
16253
+ resolveConsent,
15751
16254
  resolveFileToLayer,
15752
16255
  resolveModelTier,
15753
16256
  resolveReverseStatus,
15754
16257
  resolveRuleSeverity,
15755
16258
  resolveSessionDir,
16259
+ resolveStability,
15756
16260
  resolveStreamPath,
15757
16261
  resolveThresholds,
15758
16262
  runAll,
@@ -15774,6 +16278,8 @@ var VERSION = "0.21.1";
15774
16278
  scoreRoadmapCandidates,
15775
16279
  searchSymbols,
15776
16280
  secretRules,
16281
+ send,
16282
+ serializeEnvelope,
15777
16283
  serializeRoadmap,
15778
16284
  setActiveStream,
15779
16285
  sharpEdgesRules,
@@ -15784,6 +16290,7 @@ var VERSION = "0.21.1";
15784
16290
  syncRoadmap,
15785
16291
  syncToExternal,
15786
16292
  tagUncitedFindings,
16293
+ topSkills,
15787
16294
  touchStream,
15788
16295
  trackAction,
15789
16296
  unfoldRange,