@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 +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +206 -29
- package/dist/index.mjs +205 -29
- package/package.json +2 -2
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(
|
|
130
|
+
async function fileExists(path3) {
|
|
130
131
|
try {
|
|
131
|
-
await accessAsync(
|
|
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(
|
|
138
|
+
async function readFileContent(path3) {
|
|
138
139
|
try {
|
|
139
|
-
const content = await readFileAsync(
|
|
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
|
|
188
|
-
const pathDisplay =
|
|
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 "${
|
|
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(
|
|
409
|
-
return
|
|
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(
|
|
415
|
-
const contentResult = await readFileContent(
|
|
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:
|
|
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)(
|
|
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(
|
|
557
|
-
const targetName = (0, import_path3.basename)(
|
|
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 "${
|
|
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
|
|
1061
|
-
return
|
|
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(
|
|
1131
|
-
const contentResult = await readFileContent(
|
|
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: ${
|
|
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:
|
|
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 ${
|
|
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(
|
|
1440
|
-
const contentResult = await readFileContent(
|
|
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: ${
|
|
1446
|
-
{ file:
|
|
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 =
|
|
1453
|
+
const type = path3.endsWith(".md") ? "markdown" : "text";
|
|
1453
1454
|
return (0, import_types.Ok)({
|
|
1454
|
-
path:
|
|
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(
|
|
21
|
+
async function fileExists(path3) {
|
|
22
22
|
try {
|
|
23
|
-
await accessAsync(
|
|
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(
|
|
29
|
+
async function readFileContent(path3) {
|
|
30
30
|
try {
|
|
31
|
-
const content = await readFileAsync(
|
|
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
|
|
80
|
-
const pathDisplay =
|
|
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 "${
|
|
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(
|
|
301
|
-
return
|
|
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(
|
|
307
|
-
const contentResult = await readFileContent(
|
|
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:
|
|
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(
|
|
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(
|
|
449
|
-
const targetName = basename2(
|
|
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 "${
|
|
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
|
|
953
|
-
return
|
|
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(
|
|
1023
|
-
const contentResult = await readFileContent(
|
|
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: ${
|
|
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:
|
|
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 ${
|
|
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(
|
|
1332
|
-
const contentResult = await readFileContent(
|
|
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: ${
|
|
1338
|
-
{ file:
|
|
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 =
|
|
1344
|
+
const type = path3.endsWith(".md") ? "markdown" : "text";
|
|
1345
1345
|
return Ok({
|
|
1346
|
-
path:
|
|
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.
|
|
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
|
|
44
|
+
"@harness-engineering/types": "0.1.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@vitest/coverage-v8": "^4.0.18",
|