@harness-engineering/core 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { Result, WorkflowStep, WorkflowStepResult, Workflow, WorkflowResult, SkillLifecycleHooks, SkillContext, SkillResult, TurnContext } from '@harness-engineering/types';
1
+ import { Result, WorkflowStep, WorkflowStepResult, Workflow, WorkflowResult, SkillLifecycleHooks, SkillContext, SkillResult, TurnContext, CICheckName, CIFailOnSeverity, CICheckReport } from '@harness-engineering/types';
2
2
  export * from '@harness-engineering/types';
3
3
  import { z } from 'zod';
4
4
 
@@ -2251,6 +2251,14 @@ type TurnExecutor = (context: TurnContext) => Promise<{
2251
2251
  declare function runPipeline(initialContext: SkillContext, executor: SkillExecutor, options?: PipelineOptions): Promise<PipelineResult>;
2252
2252
  declare function runMultiTurnPipeline(initialContext: SkillContext, turnExecutor: TurnExecutor, options?: PipelineOptions): Promise<PipelineResult>;
2253
2253
 
2254
+ interface RunCIChecksInput {
2255
+ projectRoot: string;
2256
+ config: Record<string, unknown>;
2257
+ skip?: CICheckName[];
2258
+ failOn?: CIFailOnSeverity;
2259
+ }
2260
+ declare function runCIChecks(input: RunCIChecksInput): Promise<Result<CICheckReport, Error>>;
2261
+
2254
2262
  /**
2255
2263
  * @harness-engineering/core
2256
2264
  *
@@ -2259,4 +2267,4 @@ declare function runMultiTurnPipeline(initialContext: SkillContext, turnExecutor
2259
2267
 
2260
2268
  declare const VERSION = "0.6.0";
2261
2269
 
2262
- export { type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentType, type AgentsMapConfig, type BaseError, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommitFormat, type CommitValidation, type ConfigError, type ConfigPattern, ConsoleSink, type ConstraintError, type ContextError, type ContextFilterResult, type Convention, type CoverageOptions, type CoverageReport, type CustomRule, type CustomRuleResult, DEFAULT_STATE, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type Import, type InlineReference, type IntegrityReport, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type Metric, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineOptions, type PipelineResult, REQUIRED_SECTIONS, type ReachabilityNode, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewItem, type SelfReviewConfig, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StructureValidation, type Suggestion, type SuggestionReport, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type TurnExecutor, TypeScriptParser, type UnusedImport, VERSION, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, archiveFailures, buildDependencyGraph, buildSnapshot, checkDocCoverage, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createError, createFixes, createParseError, createSelfReview, defineLayer, detectCircularDeps, detectCircularDepsInFiles, detectDeadCode, detectDocDrift, detectPatternViolations, executeWorkflow, extractMarkdownLinks, extractSections, generateAgentsMap, generateSuggestions, getActionEmitter, getFeedbackConfig, getPhaseCategories, loadFailures, loadHandoff, loadRelevantLearnings, loadState, logAgentAction, parseDiff, previewFix, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, runMechanicalGate, runMultiTurnPipeline, runPipeline, saveHandoff, saveState, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateKnowledgeMap, validatePatternConfig };
2270
+ export { type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentType, type AgentsMapConfig, type BaseError, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommitFormat, type CommitValidation, type ConfigError, type ConfigPattern, ConsoleSink, type ConstraintError, type ContextError, type ContextFilterResult, type Convention, type CoverageOptions, type CoverageReport, type CustomRule, type CustomRuleResult, DEFAULT_STATE, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type Import, type InlineReference, type IntegrityReport, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type Metric, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineOptions, type PipelineResult, REQUIRED_SECTIONS, type ReachabilityNode, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewItem, type RunCIChecksInput, type SelfReviewConfig, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StructureValidation, type Suggestion, type SuggestionReport, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type TurnExecutor, TypeScriptParser, type UnusedImport, VERSION, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, archiveFailures, buildDependencyGraph, buildSnapshot, checkDocCoverage, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createError, createFixes, createParseError, createSelfReview, defineLayer, detectCircularDeps, detectCircularDepsInFiles, detectDeadCode, detectDocDrift, detectPatternViolations, executeWorkflow, extractMarkdownLinks, extractSections, generateAgentsMap, generateSuggestions, getActionEmitter, getFeedbackConfig, getPhaseCategories, loadFailures, loadHandoff, loadRelevantLearnings, loadState, logAgentAction, parseDiff, previewFix, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, runCIChecks, runMechanicalGate, runMultiTurnPipeline, runPipeline, saveHandoff, saveState, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateKnowledgeMap, validatePatternConfig };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Result, WorkflowStep, WorkflowStepResult, Workflow, WorkflowResult, SkillLifecycleHooks, SkillContext, SkillResult, TurnContext } from '@harness-engineering/types';
1
+ import { Result, WorkflowStep, WorkflowStepResult, Workflow, WorkflowResult, SkillLifecycleHooks, SkillContext, SkillResult, TurnContext, CICheckName, CIFailOnSeverity, CICheckReport } from '@harness-engineering/types';
2
2
  export * from '@harness-engineering/types';
3
3
  import { z } from 'zod';
4
4
 
@@ -2251,6 +2251,14 @@ type TurnExecutor = (context: TurnContext) => Promise<{
2251
2251
  declare function runPipeline(initialContext: SkillContext, executor: SkillExecutor, options?: PipelineOptions): Promise<PipelineResult>;
2252
2252
  declare function runMultiTurnPipeline(initialContext: SkillContext, turnExecutor: TurnExecutor, options?: PipelineOptions): Promise<PipelineResult>;
2253
2253
 
2254
+ interface RunCIChecksInput {
2255
+ projectRoot: string;
2256
+ config: Record<string, unknown>;
2257
+ skip?: CICheckName[];
2258
+ failOn?: CIFailOnSeverity;
2259
+ }
2260
+ declare function runCIChecks(input: RunCIChecksInput): Promise<Result<CICheckReport, Error>>;
2261
+
2254
2262
  /**
2255
2263
  * @harness-engineering/core
2256
2264
  *
@@ -2259,4 +2267,4 @@ declare function runMultiTurnPipeline(initialContext: SkillContext, turnExecutor
2259
2267
 
2260
2268
  declare const VERSION = "0.6.0";
2261
2269
 
2262
- export { type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentType, type AgentsMapConfig, type BaseError, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommitFormat, type CommitValidation, type ConfigError, type ConfigPattern, ConsoleSink, type ConstraintError, type ContextError, type ContextFilterResult, type Convention, type CoverageOptions, type CoverageReport, type CustomRule, type CustomRuleResult, DEFAULT_STATE, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type Import, type InlineReference, type IntegrityReport, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type Metric, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineOptions, type PipelineResult, REQUIRED_SECTIONS, type ReachabilityNode, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewItem, type SelfReviewConfig, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StructureValidation, type Suggestion, type SuggestionReport, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type TurnExecutor, TypeScriptParser, type UnusedImport, VERSION, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, archiveFailures, buildDependencyGraph, buildSnapshot, checkDocCoverage, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createError, createFixes, createParseError, createSelfReview, defineLayer, detectCircularDeps, detectCircularDepsInFiles, detectDeadCode, detectDocDrift, detectPatternViolations, executeWorkflow, extractMarkdownLinks, extractSections, generateAgentsMap, generateSuggestions, getActionEmitter, getFeedbackConfig, getPhaseCategories, loadFailures, loadHandoff, loadRelevantLearnings, loadState, logAgentAction, parseDiff, previewFix, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, runMechanicalGate, runMultiTurnPipeline, runPipeline, saveHandoff, saveState, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateKnowledgeMap, validatePatternConfig };
2270
+ export { type AST, type ActionContext, type ActionEvent, type ActionEventHandler, type ActionEventType, type ActionResult, type ActionSink, type ActionTracker, type ActionType, type AgentAction, AgentActionEmitter, type AgentConfig, type AgentExecutor, type AgentMapLink, type AgentMapSection, type AgentMapValidation, type AgentProcess, type AgentType, type AgentsMapConfig, type BaseError, type BoundaryDefinition, type BoundaryValidation, type BoundaryValidator, type BoundaryViolation, type BrokenLink, type ChangedFile, ChecklistBuilder, type CircularDependency, type CircularDepsResult, type CodeBlock, type CodeChanges, type CodePattern, type CodeReference, type CodebaseSnapshot, type CommitFormat, type CommitValidation, type ConfigError, type ConfigPattern, ConsoleSink, type ConstraintError, type ContextError, type ContextFilterResult, type Convention, type CoverageOptions, type CoverageReport, type CustomRule, type CustomRuleResult, DEFAULT_STATE, type DeadCodeConfig, type DeadCodeReport, type DeadExport, type DeadFile, type DeadInternal, type DependencyEdge, type DependencyGraph, type DependencyValidation, type DependencyViolation, type DocumentationDrift, type DocumentationFile, type DocumentationGap, type DriftConfig, type DriftReport, EntropyAnalyzer, type EntropyConfig, EntropyConfigSchema, type EntropyError, type EntropyReport, type ExecutorHealth, type Export, type ExportMap, type FailureEntry, FailureEntrySchema, type FeedbackConfig, type FeedbackError$1 as FeedbackError, type FileCategory, FileSink, type Fix, type FixConfig, type FixResult, type FixType, type ForbiddenPattern, type GateConfig, GateConfigSchema, type GateResult, GateResultSchema, type GenerationSection, type Handoff, HandoffSchema, type HarnessState, HarnessStateSchema, type HealthCheckResult, type Import, type InlineReference, type IntegrityReport, type InternalSymbol, type JSDocComment, type LanguageParser, type Layer, type LayerConfig, type LogEntry, type LogFilter, type Metric, NoOpExecutor, NoOpSink, NoOpTelemetryAdapter, type ParseError, type PatternConfig, PatternConfigSchema, type PatternMatch, type PatternReport, type PatternViolation, type PeerReview, type PeerReviewOptions, type PipelineOptions, type PipelineResult, REQUIRED_SECTIONS, type ReachabilityNode, type ReviewChecklist, type ReviewComment, type ReviewContext, type ReviewItem, type RunCIChecksInput, type SelfReviewConfig, type SkillExecutor, type SourceFile, type Span, type SpanEvent, type StepExecutor, type StructureValidation, type Suggestion, type SuggestionReport, type TelemetryAdapter, type TelemetryHealth, type TimeRange, type TokenBudget, type TokenBudgetOverrides, type Trace, type TurnExecutor, TypeScriptParser, type UnusedImport, VERSION, type ValidationError, type WorkflowPhase, analyzeDiff, appendFailure, appendLearning, applyFixes, archiveFailures, buildDependencyGraph, buildSnapshot, checkDocCoverage, configureFeedback, contextBudget, contextFilter, createBoundaryValidator, createError, createFixes, createParseError, createSelfReview, defineLayer, detectCircularDeps, detectCircularDepsInFiles, detectDeadCode, detectDocDrift, detectPatternViolations, executeWorkflow, extractMarkdownLinks, extractSections, generateAgentsMap, generateSuggestions, getActionEmitter, getFeedbackConfig, getPhaseCategories, loadFailures, loadHandoff, loadRelevantLearnings, loadState, logAgentAction, parseDiff, previewFix, requestMultiplePeerReviews, requestPeerReview, resetFeedbackConfig, resolveFileToLayer, runCIChecks, runMechanicalGate, runMultiTurnPipeline, runPipeline, saveHandoff, saveState, trackAction, validateAgentsMap, validateBoundaries, validateCommitMessage, validateConfig, validateDependencies, validateFileStructure, validateKnowledgeMap, validatePatternConfig };
package/dist/index.js CHANGED
@@ -91,6 +91,7 @@ __export(index_exports, {
91
91
  requestPeerReview: () => requestPeerReview,
92
92
  resetFeedbackConfig: () => resetFeedbackConfig,
93
93
  resolveFileToLayer: () => resolveFileToLayer,
94
+ runCIChecks: () => runCIChecks,
94
95
  runMechanicalGate: () => runMechanicalGate,
95
96
  runMultiTurnPipeline: () => runMultiTurnPipeline,
96
97
  runPipeline: () => runPipeline,
@@ -126,17 +127,17 @@ var import_util = require("util");
126
127
  var import_glob = require("glob");
127
128
  var accessAsync = (0, import_util.promisify)(import_fs.access);
128
129
  var readFileAsync = (0, import_util.promisify)(import_fs.readFile);
129
- async function fileExists(path2) {
130
+ async function fileExists(path3) {
130
131
  try {
131
- await accessAsync(path2, import_fs.constants.F_OK);
132
+ await accessAsync(path3, import_fs.constants.F_OK);
132
133
  return true;
133
134
  } catch {
134
135
  return false;
135
136
  }
136
137
  }
137
- async function readFileContent(path2) {
138
+ async function readFileContent(path3) {
138
139
  try {
139
- const content = await readFileAsync(path2, "utf-8");
140
+ const content = await readFileAsync(path3, "utf-8");
140
141
  return (0, import_types.Ok)(content);
141
142
  } catch (error) {
142
143
  return (0, import_types.Err)(error);
@@ -184,15 +185,15 @@ function validateConfig(data, schema) {
184
185
  let message = "Configuration validation failed";
185
186
  const suggestions = [];
186
187
  if (firstError) {
187
- const path2 = firstError.path.join(".");
188
- const pathDisplay = path2 ? ` at "${path2}"` : "";
188
+ const path3 = firstError.path.join(".");
189
+ const pathDisplay = path3 ? ` at "${path3}"` : "";
189
190
  if (firstError.code === "invalid_type") {
190
191
  const received = firstError.received;
191
192
  const expected = firstError.expected;
192
193
  if (received === "undefined") {
193
194
  code = "MISSING_FIELD";
194
195
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
195
- suggestions.push(`Field "${path2}" is required and must be of type "${expected}"`);
196
+ suggestions.push(`Field "${path3}" is required and must be of type "${expected}"`);
196
197
  } else {
197
198
  code = "INVALID_TYPE";
198
199
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -405,27 +406,27 @@ function extractSections(content) {
405
406
  return result;
406
407
  });
407
408
  }
408
- function isExternalLink(path2) {
409
- return path2.startsWith("http://") || path2.startsWith("https://") || path2.startsWith("#") || path2.startsWith("mailto:");
409
+ function isExternalLink(path3) {
410
+ return path3.startsWith("http://") || path3.startsWith("https://") || path3.startsWith("#") || path3.startsWith("mailto:");
410
411
  }
411
412
  function resolveLinkPath(linkPath, baseDir) {
412
413
  return linkPath.startsWith(".") ? (0, import_path.join)(baseDir, linkPath) : linkPath;
413
414
  }
414
- async function validateAgentsMap(path2 = "./AGENTS.md") {
415
- const contentResult = await readFileContent(path2);
415
+ async function validateAgentsMap(path3 = "./AGENTS.md") {
416
+ const contentResult = await readFileContent(path3);
416
417
  if (!contentResult.ok) {
417
418
  return (0, import_types.Err)(
418
419
  createError(
419
420
  "PARSE_ERROR",
420
421
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
421
- { path: path2 },
422
+ { path: path3 },
422
423
  ["Ensure the file exists", "Check file permissions"]
423
424
  )
424
425
  );
425
426
  }
426
427
  const content = contentResult.value;
427
428
  const sections = extractSections(content);
428
- const baseDir = (0, import_path.dirname)(path2);
429
+ const baseDir = (0, import_path.dirname)(path3);
429
430
  const sectionTitles = sections.map((s) => s.title);
430
431
  const missingSections = REQUIRED_SECTIONS.filter(
431
432
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -553,8 +554,8 @@ async function checkDocCoverage(domain, options = {}) {
553
554
 
554
555
  // src/context/knowledge-map.ts
555
556
  var import_path3 = require("path");
556
- function suggestFix(path2, existingFiles) {
557
- const targetName = (0, import_path3.basename)(path2).toLowerCase();
557
+ function suggestFix(path3, existingFiles) {
558
+ const targetName = (0, import_path3.basename)(path3).toLowerCase();
558
559
  const similar = existingFiles.find((file) => {
559
560
  const fileName = (0, import_path3.basename)(file).toLowerCase();
560
561
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -562,7 +563,7 @@ function suggestFix(path2, existingFiles) {
562
563
  if (similar) {
563
564
  return `Did you mean "${similar}"?`;
564
565
  }
565
- return `Create the file "${path2}" or remove the link`;
566
+ return `Create the file "${path3}" or remove the link`;
566
567
  }
567
568
  async function validateKnowledgeMap(rootDir = process.cwd()) {
568
569
  const agentsPath = (0, import_path3.join)(rootDir, "AGENTS.md");
@@ -1057,8 +1058,8 @@ function createBoundaryValidator(schema, name) {
1057
1058
  return (0, import_types.Ok)(result.data);
1058
1059
  }
1059
1060
  const suggestions = result.error.issues.map((issue) => {
1060
- const path2 = issue.path.join(".");
1061
- return path2 ? `${path2}: ${issue.message}` : issue.message;
1061
+ const path3 = issue.path.join(".");
1062
+ return path3 ? `${path3}: ${issue.message}` : issue.message;
1062
1063
  });
1063
1064
  return (0, import_types.Err)(
1064
1065
  createError(
@@ -1127,11 +1128,11 @@ function walk(node, visitor) {
1127
1128
  var TypeScriptParser = class {
1128
1129
  name = "typescript";
1129
1130
  extensions = [".ts", ".tsx", ".mts", ".cts"];
1130
- async parseFile(path2) {
1131
- const contentResult = await readFileContent(path2);
1131
+ async parseFile(path3) {
1132
+ const contentResult = await readFileContent(path3);
1132
1133
  if (!contentResult.ok) {
1133
1134
  return (0, import_types.Err)(
1134
- createParseError("NOT_FOUND", `File not found: ${path2}`, { path: path2 }, [
1135
+ createParseError("NOT_FOUND", `File not found: ${path3}`, { path: path3 }, [
1135
1136
  "Check that the file exists",
1136
1137
  "Verify the path is correct"
1137
1138
  ])
@@ -1141,7 +1142,7 @@ var TypeScriptParser = class {
1141
1142
  const ast = (0, import_typescript_estree.parse)(contentResult.value, {
1142
1143
  loc: true,
1143
1144
  range: true,
1144
- jsx: path2.endsWith(".tsx"),
1145
+ jsx: path3.endsWith(".tsx"),
1145
1146
  errorOnUnknownASTType: false
1146
1147
  });
1147
1148
  return (0, import_types.Ok)({
@@ -1152,7 +1153,7 @@ var TypeScriptParser = class {
1152
1153
  } catch (e) {
1153
1154
  const error = e;
1154
1155
  return (0, import_types.Err)(
1155
- createParseError("SYNTAX_ERROR", `Failed to parse ${path2}: ${error.message}`, { path: path2 }, [
1156
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path3}: ${error.message}`, { path: path3 }, [
1156
1157
  "Check for syntax errors in the file",
1157
1158
  "Ensure valid TypeScript syntax"
1158
1159
  ])
@@ -1436,22 +1437,22 @@ function extractInlineRefs(content) {
1436
1437
  }
1437
1438
  return refs;
1438
1439
  }
1439
- async function parseDocumentationFile(path2) {
1440
- const contentResult = await readFileContent(path2);
1440
+ async function parseDocumentationFile(path3) {
1441
+ const contentResult = await readFileContent(path3);
1441
1442
  if (!contentResult.ok) {
1442
1443
  return (0, import_types.Err)(
1443
1444
  createEntropyError(
1444
1445
  "PARSE_ERROR",
1445
- `Failed to read documentation file: ${path2}`,
1446
- { file: path2 },
1446
+ `Failed to read documentation file: ${path3}`,
1447
+ { file: path3 },
1447
1448
  ["Check that the file exists"]
1448
1449
  )
1449
1450
  );
1450
1451
  }
1451
1452
  const content = contentResult.value;
1452
- const type = path2.endsWith(".md") ? "markdown" : "text";
1453
+ const type = path3.endsWith(".md") ? "markdown" : "text";
1453
1454
  return (0, import_types.Ok)({
1454
- path: path2,
1455
+ path: path3,
1455
1456
  type,
1456
1457
  content,
1457
1458
  codeBlocks: extractCodeBlocks(content),
@@ -3962,6 +3963,181 @@ async function runMultiTurnPipeline(initialContext, turnExecutor, options) {
3962
3963
  };
3963
3964
  }
3964
3965
 
3966
+ // src/ci/check-orchestrator.ts
3967
+ var path2 = __toESM(require("path"));
3968
+ var ALL_CHECKS = ["validate", "deps", "docs", "entropy", "phase-gate"];
3969
+ async function runSingleCheck(name, projectRoot, config) {
3970
+ const start = Date.now();
3971
+ const issues = [];
3972
+ try {
3973
+ switch (name) {
3974
+ case "validate": {
3975
+ const agentsPath = path2.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
3976
+ const result = await validateAgentsMap(agentsPath);
3977
+ if (!result.ok) {
3978
+ issues.push({ severity: "error", message: result.error.message });
3979
+ } else if (!result.value.valid) {
3980
+ if (result.value.errors) {
3981
+ for (const err of result.value.errors) {
3982
+ issues.push({ severity: "error", message: err.message });
3983
+ }
3984
+ }
3985
+ for (const section of result.value.missingSections) {
3986
+ issues.push({ severity: "warning", message: `Missing section: ${section}` });
3987
+ }
3988
+ for (const link of result.value.brokenLinks) {
3989
+ issues.push({
3990
+ severity: "warning",
3991
+ message: `Broken link: ${link.text} \u2192 ${link.path}`,
3992
+ file: link.path
3993
+ });
3994
+ }
3995
+ }
3996
+ break;
3997
+ }
3998
+ case "deps": {
3999
+ const layers = config.layers;
4000
+ if (layers && layers.length > 0) {
4001
+ const parser = new TypeScriptParser();
4002
+ const result = await validateDependencies({
4003
+ layers,
4004
+ rootDir: projectRoot,
4005
+ parser
4006
+ });
4007
+ if (!result.ok) {
4008
+ issues.push({ severity: "error", message: result.error.message });
4009
+ } else if (result.value.violations.length > 0) {
4010
+ for (const v of result.value.violations) {
4011
+ issues.push({
4012
+ severity: "error",
4013
+ message: `${v.reason}: ${v.file} imports ${v.imports} (${v.fromLayer} \u2192 ${v.toLayer})`,
4014
+ file: v.file,
4015
+ line: v.line
4016
+ });
4017
+ }
4018
+ }
4019
+ }
4020
+ break;
4021
+ }
4022
+ case "docs": {
4023
+ const docsDir = path2.join(projectRoot, config.docsDir ?? "docs");
4024
+ const result = await checkDocCoverage("project", { docsDir });
4025
+ if (!result.ok) {
4026
+ issues.push({ severity: "warning", message: result.error.message });
4027
+ } else if (result.value.gaps.length > 0) {
4028
+ for (const gap of result.value.gaps) {
4029
+ issues.push({
4030
+ severity: "warning",
4031
+ message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
4032
+ file: gap.file
4033
+ });
4034
+ }
4035
+ }
4036
+ break;
4037
+ }
4038
+ case "entropy": {
4039
+ const analyzer = new EntropyAnalyzer({
4040
+ rootDir: projectRoot,
4041
+ analyze: { drift: true, deadCode: true, patterns: false }
4042
+ });
4043
+ const result = await analyzer.analyze();
4044
+ if (!result.ok) {
4045
+ issues.push({ severity: "warning", message: result.error.message });
4046
+ } else {
4047
+ const report = result.value;
4048
+ if (report.drift) {
4049
+ for (const drift of report.drift.drifts) {
4050
+ issues.push({
4051
+ severity: "warning",
4052
+ message: `Doc drift (${drift.type}): ${drift.details}`,
4053
+ file: drift.docFile,
4054
+ line: drift.line
4055
+ });
4056
+ }
4057
+ }
4058
+ if (report.deadCode) {
4059
+ for (const dead of report.deadCode.deadExports) {
4060
+ issues.push({
4061
+ severity: "warning",
4062
+ message: `Dead export: ${dead.name}`,
4063
+ file: dead.file,
4064
+ line: dead.line
4065
+ });
4066
+ }
4067
+ }
4068
+ }
4069
+ break;
4070
+ }
4071
+ case "phase-gate": {
4072
+ const phaseGates = config.phaseGates;
4073
+ if (!phaseGates?.enabled) {
4074
+ break;
4075
+ }
4076
+ issues.push({
4077
+ severity: "warning",
4078
+ message: "Phase gate is enabled but requires CLI context. Run `harness check-phase-gate` separately for full validation."
4079
+ });
4080
+ break;
4081
+ }
4082
+ }
4083
+ } catch (error) {
4084
+ issues.push({
4085
+ severity: "error",
4086
+ message: `Check '${name}' threw: ${error instanceof Error ? error.message : String(error)}`
4087
+ });
4088
+ }
4089
+ const hasErrors = issues.some((i) => i.severity === "error");
4090
+ const hasWarnings = issues.some((i) => i.severity === "warning");
4091
+ const status = hasErrors ? "fail" : hasWarnings ? "warn" : "pass";
4092
+ return {
4093
+ name,
4094
+ status,
4095
+ issues,
4096
+ durationMs: Date.now() - start
4097
+ };
4098
+ }
4099
+ function buildSummary(checks) {
4100
+ return {
4101
+ total: checks.length,
4102
+ passed: checks.filter((c) => c.status === "pass").length,
4103
+ failed: checks.filter((c) => c.status === "fail").length,
4104
+ warnings: checks.filter((c) => c.status === "warn").length,
4105
+ skipped: checks.filter((c) => c.status === "skip").length
4106
+ };
4107
+ }
4108
+ function determineExitCode(summary, failOn = "error") {
4109
+ if (summary.failed > 0) return 1;
4110
+ if (failOn === "warning" && summary.warnings > 0) return 1;
4111
+ return 0;
4112
+ }
4113
+ async function runCIChecks(input) {
4114
+ const { projectRoot, config, skip = [], failOn = "error" } = input;
4115
+ try {
4116
+ const checks = [];
4117
+ for (const name of ALL_CHECKS) {
4118
+ if (skip.includes(name)) {
4119
+ checks.push({ name, status: "skip", issues: [], durationMs: 0 });
4120
+ } else {
4121
+ const result = await runSingleCheck(name, projectRoot, config);
4122
+ checks.push(result);
4123
+ }
4124
+ }
4125
+ const summary = buildSummary(checks);
4126
+ const exitCode = determineExitCode(summary, failOn);
4127
+ const report = {
4128
+ version: 1,
4129
+ project: config.name ?? "unknown",
4130
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4131
+ checks,
4132
+ summary,
4133
+ exitCode
4134
+ };
4135
+ return (0, import_types.Ok)(report);
4136
+ } catch (error) {
4137
+ return (0, import_types.Err)(error instanceof Error ? error : new Error(String(error)));
4138
+ }
4139
+ }
4140
+
3965
4141
  // src/index.ts
3966
4142
  var VERSION = "0.6.0";
3967
4143
  // Annotate the CommonJS export names for ESM import in node:
@@ -4026,6 +4202,7 @@ var VERSION = "0.6.0";
4026
4202
  requestPeerReview,
4027
4203
  resetFeedbackConfig,
4028
4204
  resolveFileToLayer,
4205
+ runCIChecks,
4029
4206
  runMechanicalGate,
4030
4207
  runMultiTurnPipeline,
4031
4208
  runPipeline,
package/dist/index.mjs CHANGED
@@ -18,17 +18,17 @@ import { promisify } from "util";
18
18
  import { glob } from "glob";
19
19
  var accessAsync = promisify(access);
20
20
  var readFileAsync = promisify(readFile);
21
- async function fileExists(path2) {
21
+ async function fileExists(path3) {
22
22
  try {
23
- await accessAsync(path2, constants.F_OK);
23
+ await accessAsync(path3, constants.F_OK);
24
24
  return true;
25
25
  } catch {
26
26
  return false;
27
27
  }
28
28
  }
29
- async function readFileContent(path2) {
29
+ async function readFileContent(path3) {
30
30
  try {
31
- const content = await readFileAsync(path2, "utf-8");
31
+ const content = await readFileAsync(path3, "utf-8");
32
32
  return Ok(content);
33
33
  } catch (error) {
34
34
  return Err(error);
@@ -76,15 +76,15 @@ function validateConfig(data, schema) {
76
76
  let message = "Configuration validation failed";
77
77
  const suggestions = [];
78
78
  if (firstError) {
79
- const path2 = firstError.path.join(".");
80
- const pathDisplay = path2 ? ` at "${path2}"` : "";
79
+ const path3 = firstError.path.join(".");
80
+ const pathDisplay = path3 ? ` at "${path3}"` : "";
81
81
  if (firstError.code === "invalid_type") {
82
82
  const received = firstError.received;
83
83
  const expected = firstError.expected;
84
84
  if (received === "undefined") {
85
85
  code = "MISSING_FIELD";
86
86
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
87
- suggestions.push(`Field "${path2}" is required and must be of type "${expected}"`);
87
+ suggestions.push(`Field "${path3}" is required and must be of type "${expected}"`);
88
88
  } else {
89
89
  code = "INVALID_TYPE";
90
90
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -297,27 +297,27 @@ function extractSections(content) {
297
297
  return result;
298
298
  });
299
299
  }
300
- function isExternalLink(path2) {
301
- return path2.startsWith("http://") || path2.startsWith("https://") || path2.startsWith("#") || path2.startsWith("mailto:");
300
+ function isExternalLink(path3) {
301
+ return path3.startsWith("http://") || path3.startsWith("https://") || path3.startsWith("#") || path3.startsWith("mailto:");
302
302
  }
303
303
  function resolveLinkPath(linkPath, baseDir) {
304
304
  return linkPath.startsWith(".") ? join(baseDir, linkPath) : linkPath;
305
305
  }
306
- async function validateAgentsMap(path2 = "./AGENTS.md") {
307
- const contentResult = await readFileContent(path2);
306
+ async function validateAgentsMap(path3 = "./AGENTS.md") {
307
+ const contentResult = await readFileContent(path3);
308
308
  if (!contentResult.ok) {
309
309
  return Err(
310
310
  createError(
311
311
  "PARSE_ERROR",
312
312
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
313
- { path: path2 },
313
+ { path: path3 },
314
314
  ["Ensure the file exists", "Check file permissions"]
315
315
  )
316
316
  );
317
317
  }
318
318
  const content = contentResult.value;
319
319
  const sections = extractSections(content);
320
- const baseDir = dirname(path2);
320
+ const baseDir = dirname(path3);
321
321
  const sectionTitles = sections.map((s) => s.title);
322
322
  const missingSections = REQUIRED_SECTIONS.filter(
323
323
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -445,8 +445,8 @@ async function checkDocCoverage(domain, options = {}) {
445
445
 
446
446
  // src/context/knowledge-map.ts
447
447
  import { join as join2, basename as basename2, relative as relative2 } from "path";
448
- function suggestFix(path2, existingFiles) {
449
- const targetName = basename2(path2).toLowerCase();
448
+ function suggestFix(path3, existingFiles) {
449
+ const targetName = basename2(path3).toLowerCase();
450
450
  const similar = existingFiles.find((file) => {
451
451
  const fileName = basename2(file).toLowerCase();
452
452
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -454,7 +454,7 @@ function suggestFix(path2, existingFiles) {
454
454
  if (similar) {
455
455
  return `Did you mean "${similar}"?`;
456
456
  }
457
- return `Create the file "${path2}" or remove the link`;
457
+ return `Create the file "${path3}" or remove the link`;
458
458
  }
459
459
  async function validateKnowledgeMap(rootDir = process.cwd()) {
460
460
  const agentsPath = join2(rootDir, "AGENTS.md");
@@ -949,8 +949,8 @@ function createBoundaryValidator(schema, name) {
949
949
  return Ok(result.data);
950
950
  }
951
951
  const suggestions = result.error.issues.map((issue) => {
952
- const path2 = issue.path.join(".");
953
- return path2 ? `${path2}: ${issue.message}` : issue.message;
952
+ const path3 = issue.path.join(".");
953
+ return path3 ? `${path3}: ${issue.message}` : issue.message;
954
954
  });
955
955
  return Err(
956
956
  createError(
@@ -1019,11 +1019,11 @@ function walk(node, visitor) {
1019
1019
  var TypeScriptParser = class {
1020
1020
  name = "typescript";
1021
1021
  extensions = [".ts", ".tsx", ".mts", ".cts"];
1022
- async parseFile(path2) {
1023
- const contentResult = await readFileContent(path2);
1022
+ async parseFile(path3) {
1023
+ const contentResult = await readFileContent(path3);
1024
1024
  if (!contentResult.ok) {
1025
1025
  return Err(
1026
- createParseError("NOT_FOUND", `File not found: ${path2}`, { path: path2 }, [
1026
+ createParseError("NOT_FOUND", `File not found: ${path3}`, { path: path3 }, [
1027
1027
  "Check that the file exists",
1028
1028
  "Verify the path is correct"
1029
1029
  ])
@@ -1033,7 +1033,7 @@ var TypeScriptParser = class {
1033
1033
  const ast = parse(contentResult.value, {
1034
1034
  loc: true,
1035
1035
  range: true,
1036
- jsx: path2.endsWith(".tsx"),
1036
+ jsx: path3.endsWith(".tsx"),
1037
1037
  errorOnUnknownASTType: false
1038
1038
  });
1039
1039
  return Ok({
@@ -1044,7 +1044,7 @@ var TypeScriptParser = class {
1044
1044
  } catch (e) {
1045
1045
  const error = e;
1046
1046
  return Err(
1047
- createParseError("SYNTAX_ERROR", `Failed to parse ${path2}: ${error.message}`, { path: path2 }, [
1047
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path3}: ${error.message}`, { path: path3 }, [
1048
1048
  "Check for syntax errors in the file",
1049
1049
  "Ensure valid TypeScript syntax"
1050
1050
  ])
@@ -1328,22 +1328,22 @@ function extractInlineRefs(content) {
1328
1328
  }
1329
1329
  return refs;
1330
1330
  }
1331
- async function parseDocumentationFile(path2) {
1332
- const contentResult = await readFileContent(path2);
1331
+ async function parseDocumentationFile(path3) {
1332
+ const contentResult = await readFileContent(path3);
1333
1333
  if (!contentResult.ok) {
1334
1334
  return Err(
1335
1335
  createEntropyError(
1336
1336
  "PARSE_ERROR",
1337
- `Failed to read documentation file: ${path2}`,
1338
- { file: path2 },
1337
+ `Failed to read documentation file: ${path3}`,
1338
+ { file: path3 },
1339
1339
  ["Check that the file exists"]
1340
1340
  )
1341
1341
  );
1342
1342
  }
1343
1343
  const content = contentResult.value;
1344
- const type = path2.endsWith(".md") ? "markdown" : "text";
1344
+ const type = path3.endsWith(".md") ? "markdown" : "text";
1345
1345
  return Ok({
1346
- path: path2,
1346
+ path: path3,
1347
1347
  type,
1348
1348
  content,
1349
1349
  codeBlocks: extractCodeBlocks(content),
@@ -3854,6 +3854,181 @@ async function runMultiTurnPipeline(initialContext, turnExecutor, options) {
3854
3854
  };
3855
3855
  }
3856
3856
 
3857
+ // src/ci/check-orchestrator.ts
3858
+ import * as path2 from "path";
3859
+ var ALL_CHECKS = ["validate", "deps", "docs", "entropy", "phase-gate"];
3860
+ async function runSingleCheck(name, projectRoot, config) {
3861
+ const start = Date.now();
3862
+ const issues = [];
3863
+ try {
3864
+ switch (name) {
3865
+ case "validate": {
3866
+ const agentsPath = path2.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
3867
+ const result = await validateAgentsMap(agentsPath);
3868
+ if (!result.ok) {
3869
+ issues.push({ severity: "error", message: result.error.message });
3870
+ } else if (!result.value.valid) {
3871
+ if (result.value.errors) {
3872
+ for (const err of result.value.errors) {
3873
+ issues.push({ severity: "error", message: err.message });
3874
+ }
3875
+ }
3876
+ for (const section of result.value.missingSections) {
3877
+ issues.push({ severity: "warning", message: `Missing section: ${section}` });
3878
+ }
3879
+ for (const link of result.value.brokenLinks) {
3880
+ issues.push({
3881
+ severity: "warning",
3882
+ message: `Broken link: ${link.text} \u2192 ${link.path}`,
3883
+ file: link.path
3884
+ });
3885
+ }
3886
+ }
3887
+ break;
3888
+ }
3889
+ case "deps": {
3890
+ const layers = config.layers;
3891
+ if (layers && layers.length > 0) {
3892
+ const parser = new TypeScriptParser();
3893
+ const result = await validateDependencies({
3894
+ layers,
3895
+ rootDir: projectRoot,
3896
+ parser
3897
+ });
3898
+ if (!result.ok) {
3899
+ issues.push({ severity: "error", message: result.error.message });
3900
+ } else if (result.value.violations.length > 0) {
3901
+ for (const v of result.value.violations) {
3902
+ issues.push({
3903
+ severity: "error",
3904
+ message: `${v.reason}: ${v.file} imports ${v.imports} (${v.fromLayer} \u2192 ${v.toLayer})`,
3905
+ file: v.file,
3906
+ line: v.line
3907
+ });
3908
+ }
3909
+ }
3910
+ }
3911
+ break;
3912
+ }
3913
+ case "docs": {
3914
+ const docsDir = path2.join(projectRoot, config.docsDir ?? "docs");
3915
+ const result = await checkDocCoverage("project", { docsDir });
3916
+ if (!result.ok) {
3917
+ issues.push({ severity: "warning", message: result.error.message });
3918
+ } else if (result.value.gaps.length > 0) {
3919
+ for (const gap of result.value.gaps) {
3920
+ issues.push({
3921
+ severity: "warning",
3922
+ message: `Undocumented: ${gap.file} (suggested: ${gap.suggestedSection})`,
3923
+ file: gap.file
3924
+ });
3925
+ }
3926
+ }
3927
+ break;
3928
+ }
3929
+ case "entropy": {
3930
+ const analyzer = new EntropyAnalyzer({
3931
+ rootDir: projectRoot,
3932
+ analyze: { drift: true, deadCode: true, patterns: false }
3933
+ });
3934
+ const result = await analyzer.analyze();
3935
+ if (!result.ok) {
3936
+ issues.push({ severity: "warning", message: result.error.message });
3937
+ } else {
3938
+ const report = result.value;
3939
+ if (report.drift) {
3940
+ for (const drift of report.drift.drifts) {
3941
+ issues.push({
3942
+ severity: "warning",
3943
+ message: `Doc drift (${drift.type}): ${drift.details}`,
3944
+ file: drift.docFile,
3945
+ line: drift.line
3946
+ });
3947
+ }
3948
+ }
3949
+ if (report.deadCode) {
3950
+ for (const dead of report.deadCode.deadExports) {
3951
+ issues.push({
3952
+ severity: "warning",
3953
+ message: `Dead export: ${dead.name}`,
3954
+ file: dead.file,
3955
+ line: dead.line
3956
+ });
3957
+ }
3958
+ }
3959
+ }
3960
+ break;
3961
+ }
3962
+ case "phase-gate": {
3963
+ const phaseGates = config.phaseGates;
3964
+ if (!phaseGates?.enabled) {
3965
+ break;
3966
+ }
3967
+ issues.push({
3968
+ severity: "warning",
3969
+ message: "Phase gate is enabled but requires CLI context. Run `harness check-phase-gate` separately for full validation."
3970
+ });
3971
+ break;
3972
+ }
3973
+ }
3974
+ } catch (error) {
3975
+ issues.push({
3976
+ severity: "error",
3977
+ message: `Check '${name}' threw: ${error instanceof Error ? error.message : String(error)}`
3978
+ });
3979
+ }
3980
+ const hasErrors = issues.some((i) => i.severity === "error");
3981
+ const hasWarnings = issues.some((i) => i.severity === "warning");
3982
+ const status = hasErrors ? "fail" : hasWarnings ? "warn" : "pass";
3983
+ return {
3984
+ name,
3985
+ status,
3986
+ issues,
3987
+ durationMs: Date.now() - start
3988
+ };
3989
+ }
3990
+ function buildSummary(checks) {
3991
+ return {
3992
+ total: checks.length,
3993
+ passed: checks.filter((c) => c.status === "pass").length,
3994
+ failed: checks.filter((c) => c.status === "fail").length,
3995
+ warnings: checks.filter((c) => c.status === "warn").length,
3996
+ skipped: checks.filter((c) => c.status === "skip").length
3997
+ };
3998
+ }
3999
+ function determineExitCode(summary, failOn = "error") {
4000
+ if (summary.failed > 0) return 1;
4001
+ if (failOn === "warning" && summary.warnings > 0) return 1;
4002
+ return 0;
4003
+ }
4004
+ async function runCIChecks(input) {
4005
+ const { projectRoot, config, skip = [], failOn = "error" } = input;
4006
+ try {
4007
+ const checks = [];
4008
+ for (const name of ALL_CHECKS) {
4009
+ if (skip.includes(name)) {
4010
+ checks.push({ name, status: "skip", issues: [], durationMs: 0 });
4011
+ } else {
4012
+ const result = await runSingleCheck(name, projectRoot, config);
4013
+ checks.push(result);
4014
+ }
4015
+ }
4016
+ const summary = buildSummary(checks);
4017
+ const exitCode = determineExitCode(summary, failOn);
4018
+ const report = {
4019
+ version: 1,
4020
+ project: config.name ?? "unknown",
4021
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4022
+ checks,
4023
+ summary,
4024
+ exitCode
4025
+ };
4026
+ return Ok(report);
4027
+ } catch (error) {
4028
+ return Err(error instanceof Error ? error : new Error(String(error)));
4029
+ }
4030
+ }
4031
+
3857
4032
  // src/index.ts
3858
4033
  var VERSION = "0.6.0";
3859
4034
  export {
@@ -3917,6 +4092,7 @@ export {
3917
4092
  requestPeerReview,
3918
4093
  resetFeedbackConfig,
3919
4094
  resolveFileToLayer,
4095
+ runCIChecks,
3920
4096
  runMechanicalGate,
3921
4097
  runMultiTurnPipeline,
3922
4098
  runPipeline,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/core",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Core library for Harness Engineering toolkit",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,7 +41,7 @@
41
41
  "glob": "^10.3.0",
42
42
  "minimatch": "^10.2.4",
43
43
  "zod": "^3.22.0",
44
- "@harness-engineering/types": "0.0.1"
44
+ "@harness-engineering/types": "0.1.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@vitest/coverage-v8": "^4.0.18",