@harness-engineering/cli 1.28.1 → 2.1.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/agents/skills/claude-code/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/claude-code/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/claude-code/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/claude-code/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/claude-code/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/codex/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/codex/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/codex/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/codex/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/codex/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/cursor/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/cursor/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/cursor/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/cursor/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/cursor/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/gemini-cli/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/gemini-cli/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/package.json +1 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/bug-track-fixture/input.json +10 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/docs/solutions/bug-track/integration-issues/stalled-lease-cleanup.md +28 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/expected.json +4 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/input.json +10 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/knowledge-track-fixture/input.json +10 -0
- package/dist/agents/skills/tests/harness-compound.test.ts +86 -0
- package/dist/{agents-md-6SAMHE7H.js → agents-md-XCAWON2D.js} +3 -3
- package/dist/{architecture-5YR52NSV.js → architecture-KERHEEQZ.js} +4 -4
- package/dist/{assess-project-5X7TYQFM.js → assess-project-NPYA3UVI.js} +1 -1
- package/dist/bin/harness-mcp.js +16 -15
- package/dist/bin/harness.js +26 -25
- package/dist/{check-phase-gate-PLV2VDOL.js → check-phase-gate-GE5ALEEU.js} +5 -4
- package/dist/{chunk-KJD4J54I.js → chunk-4FVHBBPY.js} +6 -1
- package/dist/{chunk-PFM3BVVU.js → chunk-AEFZJ543.js} +1 -1
- package/dist/{chunk-S2WB4LE7.js → chunk-BMM3GXV6.js} +384 -28
- package/dist/{chunk-RYDPFIJY.js → chunk-D5FE4L2O.js} +1 -1
- package/dist/{chunk-HT7HYYGT.js → chunk-DRD7LLFC.js} +1 -1
- package/dist/{chunk-2IBXUG6J.js → chunk-EFA4OEEN.js} +2 -2
- package/dist/{chunk-JZST2WZS.js → chunk-FBQYKH7R.js} +3 -3
- package/dist/{chunk-MTPHNOJW.js → chunk-FQAJAM54.js} +506 -242
- package/dist/{chunk-R2CBBZA6.js → chunk-GCYGGQFM.js} +1 -1
- package/dist/{chunk-7JQ7HLM4.js → chunk-GHPWBWUW.js} +8 -8
- package/dist/{chunk-6L2BU4BP.js → chunk-HBQ3BK2E.js} +1 -1
- package/dist/{chunk-ZYLBIDLE.js → chunk-IIX5OJES.js} +1 -1
- package/dist/{chunk-DXGI7DL3.js → chunk-KTWKW6KJ.js} +1 -1
- package/dist/{chunk-6GXSJGSW.js → chunk-LY2TY6NE.js} +3 -3
- package/dist/{chunk-JNKALGRM.js → chunk-M4C3ZIGL.js} +5 -5
- package/dist/{chunk-RFYF7TJS.js → chunk-MAFI6UWT.js} +1701 -769
- package/dist/{chunk-BYS3TQOO.js → chunk-OXFFN3FD.js} +1 -1
- package/dist/{chunk-XHOGGZS7.js → chunk-PCX4GPNT.js} +1 -1
- package/dist/{chunk-BFBZK6BC.js → chunk-RCHXBL2M.js} +6 -6
- package/dist/{chunk-74YADB7T.js → chunk-T7MNLCUD.js} +92 -92
- package/dist/{chunk-SITVRO7K.js → chunk-URLDPALI.js} +9 -9
- package/dist/{chunk-ELJ2MXMO.js → chunk-UWIOBHZL.js} +9 -9
- package/dist/{chunk-QDRBWVVY.js → chunk-WW6AUOA3.js} +2 -2
- package/dist/{chunk-5ME3WG3G.js → chunk-YBGVZQQE.js} +5 -5
- package/dist/{chunk-YJE23GRZ.js → chunk-YG4ZBGEH.js} +39 -5
- package/dist/chunk-ZCZD7FHU.js +16 -0
- package/dist/{ci-workflow-7T2XKB3P.js → ci-workflow-A2E2RTOP.js} +3 -3
- package/dist/{dist-42AYXCAK.js → dist-D27LJR2T.js} +7 -1
- package/dist/{dist-77VNTHWV.js → dist-K22DQUYY.js} +78 -2
- package/dist/{docs-MSIJ6SDO.js → docs-GXJOFVCF.js} +5 -4
- package/dist/{engine-F4P5RBE4.js → engine-JBUIA2XO.js} +3 -3
- package/dist/{entropy-GSUTIORR.js → entropy-Y7LUT4BZ.js} +3 -3
- package/dist/{feedback-NST6T4HI.js → feedback-BHOBVKI3.js} +1 -1
- package/dist/{generate-agent-definitions-BOUGQIPA.js → generate-agent-definitions-VL3ZVR32.js} +4 -4
- package/dist/glob-helper-FZPPTGJN.js +62 -0
- package/dist/{graph-loader-IAUPGLRV.js → graph-loader-5MKHAJJF.js} +1 -1
- package/dist/index.d.ts +44 -6
- package/dist/index.js +26 -25
- package/dist/{loader-6QTJC7IN.js → loader-WCKVMDYR.js} +3 -3
- package/dist/{mcp-QFBGTUX6.js → mcp-FA2CKHFY.js} +16 -15
- package/dist/{performance-B2NAAIE5.js → performance-NISUL5AA.js} +5 -4
- package/dist/{review-pipeline-6EYMBS6B.js → review-pipeline-CHE5LJ5D.js} +3 -3
- package/dist/{runtime-VFZK6BCZ.js → runtime-3SKKEVPF.js} +3 -3
- package/dist/{scan-DB6FNYGG.js → scan-BIJYHOE7.js} +2 -1
- package/dist/{security-HRNTYHPM.js → security-MF54MY3P.js} +1 -1
- package/dist/templates/orchestrator/harness.orchestrator.md +31 -8
- package/dist/{validate-YEMAFWJE.js → validate-SIWFNTXI.js} +4 -4
- package/dist/{validate-cross-check-DGHTJFVH.js → validate-cross-check-GBX7B7CQ.js} +3 -3
- package/package.json +8 -7
- package/dist/glob-helper-VCQXK5XY.js +0 -54
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
NODE_STABILITY,
|
|
14
14
|
init_dist as init_dist2,
|
|
15
15
|
queryTraceability
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BMM3GXV6.js";
|
|
17
17
|
import {
|
|
18
18
|
__esm,
|
|
19
19
|
__export
|
|
@@ -69,17 +69,17 @@ function resolveFileToLayer(file, layers) {
|
|
|
69
69
|
}
|
|
70
70
|
return void 0;
|
|
71
71
|
}
|
|
72
|
-
async function fileExists(
|
|
72
|
+
async function fileExists(path42) {
|
|
73
73
|
try {
|
|
74
|
-
await accessAsync(
|
|
74
|
+
await accessAsync(path42, constants.F_OK);
|
|
75
75
|
return true;
|
|
76
76
|
} catch {
|
|
77
77
|
return false;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
async function readFileContent(
|
|
80
|
+
async function readFileContent(path42) {
|
|
81
81
|
try {
|
|
82
|
-
const content = await readFileAsync(
|
|
82
|
+
const content = await readFileAsync(path42, "utf-8");
|
|
83
83
|
return Ok(content);
|
|
84
84
|
} catch (error) {
|
|
85
85
|
return Err(error);
|
|
@@ -473,9 +473,9 @@ async function resolveWasmPath(grammarName) {
|
|
|
473
473
|
const { createRequire } = await import("module");
|
|
474
474
|
const require2 = createRequire(import.meta.url ?? __filename);
|
|
475
475
|
const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
|
|
476
|
-
const
|
|
477
|
-
const pkgDir =
|
|
478
|
-
return
|
|
476
|
+
const path42 = await import("path");
|
|
477
|
+
const pkgDir = path42.dirname(pkgPath);
|
|
478
|
+
return path42.join(pkgDir, "out", `${grammarName}.wasm`);
|
|
479
479
|
}
|
|
480
480
|
async function loadLanguage(lang) {
|
|
481
481
|
const grammarName = GRAMMAR_MAP[lang];
|
|
@@ -1908,11 +1908,11 @@ var init_chunk_H73442AZ = __esm({
|
|
|
1908
1908
|
TypeScriptParser = class {
|
|
1909
1909
|
name = "typescript";
|
|
1910
1910
|
extensions = [".ts", ".tsx", ".mts", ".cts"];
|
|
1911
|
-
async parseFile(
|
|
1912
|
-
const contentResult = await readFileContent(
|
|
1911
|
+
async parseFile(path42) {
|
|
1912
|
+
const contentResult = await readFileContent(path42);
|
|
1913
1913
|
if (!contentResult.ok) {
|
|
1914
1914
|
return Err(
|
|
1915
|
-
createParseError("NOT_FOUND", `File not found: ${
|
|
1915
|
+
createParseError("NOT_FOUND", `File not found: ${path42}`, { path: path42 }, [
|
|
1916
1916
|
"Check that the file exists",
|
|
1917
1917
|
"Verify the path is correct"
|
|
1918
1918
|
])
|
|
@@ -1922,7 +1922,7 @@ var init_chunk_H73442AZ = __esm({
|
|
|
1922
1922
|
const ast = parse(contentResult.value, {
|
|
1923
1923
|
loc: true,
|
|
1924
1924
|
range: true,
|
|
1925
|
-
jsx:
|
|
1925
|
+
jsx: path42.endsWith(".tsx"),
|
|
1926
1926
|
errorOnUnknownASTType: false
|
|
1927
1927
|
});
|
|
1928
1928
|
return Ok({
|
|
@@ -1933,7 +1933,7 @@ var init_chunk_H73442AZ = __esm({
|
|
|
1933
1933
|
} catch (e) {
|
|
1934
1934
|
const error = e;
|
|
1935
1935
|
return Err(
|
|
1936
|
-
createParseError("SYNTAX_ERROR", `Failed to parse ${
|
|
1936
|
+
createParseError("SYNTAX_ERROR", `Failed to parse ${path42}: ${error.message}`, { path: path42 }, [
|
|
1937
1937
|
"Check for syntax errors in the file",
|
|
1938
1938
|
"Ensure valid TypeScript syntax"
|
|
1939
1939
|
])
|
|
@@ -2248,11 +2248,11 @@ var init_chunk_H73442AZ = __esm({
|
|
|
2248
2248
|
this.extensions = extensions;
|
|
2249
2249
|
this.strategy = strategy;
|
|
2250
2250
|
}
|
|
2251
|
-
async parseFile(
|
|
2252
|
-
const contentResult = await readFileContent(
|
|
2251
|
+
async parseFile(path42) {
|
|
2252
|
+
const contentResult = await readFileContent(path42);
|
|
2253
2253
|
if (!contentResult.ok) {
|
|
2254
2254
|
return Err(
|
|
2255
|
-
createParseError("NOT_FOUND", `File not found: ${
|
|
2255
|
+
createParseError("NOT_FOUND", `File not found: ${path42}`, { path: path42 }, [
|
|
2256
2256
|
"Check that the file exists"
|
|
2257
2257
|
])
|
|
2258
2258
|
);
|
|
@@ -2268,7 +2268,7 @@ var init_chunk_H73442AZ = __esm({
|
|
|
2268
2268
|
} catch (e) {
|
|
2269
2269
|
const error = e;
|
|
2270
2270
|
return Err(
|
|
2271
|
-
createParseError("SYNTAX_ERROR", `Failed to parse ${
|
|
2271
|
+
createParseError("SYNTAX_ERROR", `Failed to parse ${path42}: ${error.message}`, { path: path42 }, [
|
|
2272
2272
|
"Check for syntax errors in the file"
|
|
2273
2273
|
])
|
|
2274
2274
|
);
|
|
@@ -2784,6 +2784,8 @@ var dist_exports = {};
|
|
|
2784
2784
|
__export(dist_exports, {
|
|
2785
2785
|
AGENT_DESCRIPTORS: () => AGENT_DESCRIPTORS,
|
|
2786
2786
|
AGREEMENT_LINE_GAP: () => AGREEMENT_LINE_GAP,
|
|
2787
|
+
ALLOWED_FIELD_KEYS: () => ALLOWED_FIELD_KEYS,
|
|
2788
|
+
ALL_SOLUTION_CATEGORIES: () => ALL_SOLUTION_CATEGORIES,
|
|
2787
2789
|
ARCHITECTURE_DESCRIPTOR: () => ARCHITECTURE_DESCRIPTOR,
|
|
2788
2790
|
AdjustedForecastSchema: () => AdjustedForecastSchema,
|
|
2789
2791
|
AgentActionEmitter: () => AgentActionEmitter,
|
|
@@ -2794,6 +2796,7 @@ __export(dist_exports, {
|
|
|
2794
2796
|
ArchDiffResultSchema: () => ArchDiffResultSchema,
|
|
2795
2797
|
ArchMetricCategorySchema: () => ArchMetricCategorySchema,
|
|
2796
2798
|
BUG_DETECTION_DESCRIPTOR: () => BUG_DETECTION_DESCRIPTOR,
|
|
2799
|
+
BUG_TRACK_CATEGORIES: () => BUG_TRACK_CATEGORIES,
|
|
2797
2800
|
BaselineManager: () => BaselineManager,
|
|
2798
2801
|
BenchmarkRunner: () => BenchmarkRunner,
|
|
2799
2802
|
BlueprintGenerator: () => BlueprintGenerator,
|
|
@@ -2811,6 +2814,7 @@ __export(dist_exports, {
|
|
|
2811
2814
|
CircularDepsCollector: () => CircularDepsCollector,
|
|
2812
2815
|
CompactionPipeline: () => CompactionPipeline,
|
|
2813
2816
|
ComplexityCollector: () => ComplexityCollector,
|
|
2817
|
+
CompoundLockHeldError: () => CompoundLockHeldError,
|
|
2814
2818
|
ConfidenceTierSchema: () => ConfidenceTierSchema,
|
|
2815
2819
|
ConfirmationSchema: () => ConfirmationSchema,
|
|
2816
2820
|
ConsoleSink: () => ConsoleSink,
|
|
@@ -2854,10 +2858,12 @@ __export(dist_exports, {
|
|
|
2854
2858
|
HandoffSchema: () => HandoffSchema,
|
|
2855
2859
|
HarnessStateSchema: () => HarnessStateSchema,
|
|
2856
2860
|
InteractionTypeSchema: () => InteractionTypeSchema,
|
|
2861
|
+
KNOWLEDGE_TRACK_CATEGORIES: () => KNOWLEDGE_TRACK_CATEGORIES,
|
|
2857
2862
|
LITELLM_PRICING_URL: () => LITELLM_PRICING_URL,
|
|
2858
2863
|
LayerViolationCollector: () => LayerViolationCollector,
|
|
2859
2864
|
LockfilePackageSchema: () => LockfilePackageSchema,
|
|
2860
2865
|
LockfileSchema: () => LockfileSchema,
|
|
2866
|
+
MOCK_ADAPTER_NAME: () => MOCK_ADAPTER_NAME,
|
|
2861
2867
|
ManifestSchema: () => ManifestSchema,
|
|
2862
2868
|
MetricResultSchema: () => MetricResultSchema,
|
|
2863
2869
|
ModuleSizeCollector: () => ModuleSizeCollector,
|
|
@@ -2866,6 +2872,9 @@ __export(dist_exports, {
|
|
|
2866
2872
|
NoOpTelemetryAdapter: () => NoOpTelemetryAdapter,
|
|
2867
2873
|
Ok: () => Ok,
|
|
2868
2874
|
OpenAICacheAdapter: () => OpenAICacheAdapter,
|
|
2875
|
+
PII_FIELD_DENYLIST: () => PII_FIELD_DENYLIST,
|
|
2876
|
+
PII_LINE_RE: () => PII_LINE_RE,
|
|
2877
|
+
PII_TOKENS: () => PII_TOKENS,
|
|
2869
2878
|
PatternConfigSchema: () => PatternConfigSchema,
|
|
2870
2879
|
PredictionEngine: () => PredictionEngine,
|
|
2871
2880
|
PredictionOptionsSchema: () => PredictionOptionsSchema,
|
|
@@ -2873,6 +2882,10 @@ __export(dist_exports, {
|
|
|
2873
2882
|
PredictionResultSchema: () => PredictionResultSchema,
|
|
2874
2883
|
PredictionWarningSchema: () => PredictionWarningSchema,
|
|
2875
2884
|
ProjectScanner: () => ProjectScanner,
|
|
2885
|
+
PulseAdapterAlreadyRegisteredError: () => PulseAdapterAlreadyRegisteredError,
|
|
2886
|
+
PulseConfigSchema: () => PulseConfigSchema,
|
|
2887
|
+
PulseDbSourceSchema: () => PulseDbSourceSchema,
|
|
2888
|
+
PulseSourcesSchema: () => PulseSourcesSchema,
|
|
2876
2889
|
QuestionSchema: () => QuestionSchema,
|
|
2877
2890
|
REQUIRED_SECTIONS: () => REQUIRED_SECTIONS,
|
|
2878
2891
|
RegressionDetector: () => RegressionDetector,
|
|
@@ -2897,6 +2910,7 @@ __export(dist_exports, {
|
|
|
2897
2910
|
SharableLayerSchema: () => SharableLayerSchema,
|
|
2898
2911
|
SharableSecurityRulesSchema: () => SharableSecurityRulesSchema,
|
|
2899
2912
|
SkillEventSchema: () => SkillEventSchema,
|
|
2913
|
+
SolutionDocFrontmatterSchema: () => SolutionDocFrontmatterSchema,
|
|
2900
2914
|
SpecImpactEstimateSchema: () => SpecImpactEstimateSchema,
|
|
2901
2915
|
SpecImpactEstimator: () => SpecImpactEstimator,
|
|
2902
2916
|
SpecImpactSignalsSchema: () => SpecImpactSignalsSchema,
|
|
@@ -2924,6 +2938,7 @@ __export(dist_exports, {
|
|
|
2924
2938
|
ViolationHistorySchema: () => ViolationHistorySchema,
|
|
2925
2939
|
ViolationSchema: () => ViolationSchema,
|
|
2926
2940
|
ViolationSnapshotSchema: () => ViolationSnapshotSchema,
|
|
2941
|
+
acquireCompoundLock: () => acquireCompoundLock,
|
|
2927
2942
|
addProvenance: () => addProvenance,
|
|
2928
2943
|
agentConfigRules: () => agentConfigRules,
|
|
2929
2944
|
aggregateAdoptionByDay: () => aggregateByDay2,
|
|
@@ -2946,6 +2961,9 @@ __export(dist_exports, {
|
|
|
2946
2961
|
archiveLearnings: () => archiveLearnings,
|
|
2947
2962
|
archiveSession: () => archiveSession,
|
|
2948
2963
|
archiveStream: () => archiveStream,
|
|
2964
|
+
assembleCandidateReport: () => assembleCandidateReport,
|
|
2965
|
+
assembleReport: () => assembleReport,
|
|
2966
|
+
assertSanitized: () => assertSanitized,
|
|
2949
2967
|
assignFeature: () => assignFeature,
|
|
2950
2968
|
buildDependencyGraph: () => buildDependencyGraph,
|
|
2951
2969
|
buildExclusionSet: () => buildExclusionSet,
|
|
@@ -2962,15 +2980,18 @@ __export(dist_exports, {
|
|
|
2962
2980
|
clearEventHashCache: () => clearEventHashCache,
|
|
2963
2981
|
clearFailuresCache: () => clearFailuresCache,
|
|
2964
2982
|
clearLearningsCache: () => clearLearningsCache,
|
|
2983
|
+
clearPulseAdapters: () => clearPulseAdapters,
|
|
2965
2984
|
clearTaint: () => clearTaint,
|
|
2966
2985
|
clusterViolations: () => clusterViolations,
|
|
2967
2986
|
collectEvents: () => collectEvents,
|
|
2968
2987
|
computeContentHash: () => computeContentHash,
|
|
2988
|
+
computeHotspots: () => computeHotspots,
|
|
2969
2989
|
computeLexicalSimilarity: () => computeLexicalSimilarity,
|
|
2970
2990
|
computeLoadPlan: () => computeLoadPlan,
|
|
2971
2991
|
computeOverallSeverity: () => computeOverallSeverity,
|
|
2972
2992
|
computeScanExitCode: () => computeScanExitCode,
|
|
2973
2993
|
computeTrustScores: () => computeTrustScores,
|
|
2994
|
+
computeWindow: () => computeWindow,
|
|
2974
2995
|
configureFeedback: () => configureFeedback,
|
|
2975
2996
|
constraintRuleId: () => constraintRuleId,
|
|
2976
2997
|
contextBudget: () => contextBudget,
|
|
@@ -2986,6 +3007,7 @@ __export(dist_exports, {
|
|
|
2986
3007
|
createRegionMap: () => createRegionMap,
|
|
2987
3008
|
createSelfReview: () => createSelfReview,
|
|
2988
3009
|
createStream: () => createStream,
|
|
3010
|
+
crossReferenceUndocumentedFixes: () => crossReferenceUndocumentedFixes,
|
|
2989
3011
|
cryptoRules: () => cryptoRules,
|
|
2990
3012
|
deduplicateCleanupFindings: () => deduplicateCleanupFindings,
|
|
2991
3013
|
deduplicateFindings: () => deduplicateFindings,
|
|
@@ -3016,6 +3038,7 @@ __export(dist_exports, {
|
|
|
3016
3038
|
extractBundle: () => extractBundle,
|
|
3017
3039
|
extractDirectoryScope: () => extractDirectoryScope,
|
|
3018
3040
|
extractFileReferences: () => extractFileReferences,
|
|
3041
|
+
extractHeadlines: () => extractHeadlines,
|
|
3019
3042
|
extractIndexEntry: () => extractIndexEntry,
|
|
3020
3043
|
extractLevel: () => extractLevel,
|
|
3021
3044
|
extractMarkdownLinks: () => extractMarkdownLinks,
|
|
@@ -3027,6 +3050,7 @@ __export(dist_exports, {
|
|
|
3027
3050
|
formatFindingBlock: () => formatFindingBlock,
|
|
3028
3051
|
formatGitHubComment: () => formatGitHubComment,
|
|
3029
3052
|
formatGitHubSummary: () => formatGitHubSummary,
|
|
3053
|
+
formatIsoWeek: () => formatIsoWeek,
|
|
3030
3054
|
formatOutline: () => formatOutline,
|
|
3031
3055
|
formatTerminalOutput: () => formatTerminalOutput,
|
|
3032
3056
|
fullSync: () => fullSync,
|
|
@@ -3042,10 +3066,12 @@ __export(dist_exports, {
|
|
|
3042
3066
|
getOutline: () => getOutline,
|
|
3043
3067
|
getParser: () => getParser,
|
|
3044
3068
|
getPhaseCategories: () => getPhaseCategories,
|
|
3069
|
+
getPulseAdapter: () => getPulseAdapter,
|
|
3045
3070
|
getStreamForBranch: () => getStreamForBranch,
|
|
3046
3071
|
getTaintFilePath: () => getTaintFilePath,
|
|
3047
3072
|
getTrustLevel: () => getTrustLevel,
|
|
3048
3073
|
getUpdateNotification: () => getUpdateNotification,
|
|
3074
|
+
gitScan: () => gitScan,
|
|
3049
3075
|
goRules: () => goRules,
|
|
3050
3076
|
injectionRules: () => injectionRules,
|
|
3051
3077
|
insecureDefaultsRules: () => insecureDefaultsRules,
|
|
@@ -3053,9 +3079,12 @@ __export(dist_exports, {
|
|
|
3053
3079
|
isErr: () => isErr,
|
|
3054
3080
|
isOk: () => isOk,
|
|
3055
3081
|
isRegression: () => isRegression,
|
|
3082
|
+
isSanitizedResult: () => isSanitizedResult,
|
|
3056
3083
|
isSmallSuggestion: () => isSmallSuggestion,
|
|
3057
3084
|
isUpdateCheckEnabled: () => isUpdateCheckEnabled,
|
|
3085
|
+
isoWeek: () => isoWeek,
|
|
3058
3086
|
listActiveSessions: () => listActiveSessions,
|
|
3087
|
+
listPulseAdapters: () => listPulseAdapters,
|
|
3059
3088
|
listStreams: () => listStreams,
|
|
3060
3089
|
listTaintedSessions: () => listTaintedSessions,
|
|
3061
3090
|
loadBudgetedLearnings: () => loadBudgetedLearnings,
|
|
@@ -3089,6 +3118,7 @@ __export(dist_exports, {
|
|
|
3089
3118
|
parseFrontmatter: () => parseFrontmatter2,
|
|
3090
3119
|
parseHarnessIgnore: () => parseHarnessIgnore,
|
|
3091
3120
|
parseLiteLLMData: () => parseLiteLLMData,
|
|
3121
|
+
parseLookback: () => parseLookback,
|
|
3092
3122
|
parseManifest: () => parseManifest,
|
|
3093
3123
|
parseProtectedRegions: () => parseProtectedRegions,
|
|
3094
3124
|
parseRoadmap: () => parseRoadmap,
|
|
@@ -3109,6 +3139,8 @@ __export(dist_exports, {
|
|
|
3109
3139
|
readSessionSection: () => readSessionSection,
|
|
3110
3140
|
readSessionSections: () => readSessionSections,
|
|
3111
3141
|
readTaint: () => readTaint,
|
|
3142
|
+
registerMockAdapter: () => registerMockAdapter,
|
|
3143
|
+
registerPulseAdapter: () => registerPulseAdapter,
|
|
3112
3144
|
removeContributions: () => removeContributions,
|
|
3113
3145
|
removeProvenance: () => removeProvenance,
|
|
3114
3146
|
requestMultiplePeerReviews: () => requestMultiplePeerReviews,
|
|
@@ -3134,6 +3166,7 @@ __export(dist_exports, {
|
|
|
3134
3166
|
runMechanicalGate: () => runMechanicalGate,
|
|
3135
3167
|
runMultiTurnPipeline: () => runMultiTurnPipeline,
|
|
3136
3168
|
runPipeline: () => runPipeline,
|
|
3169
|
+
runPulse: () => runPulse,
|
|
3137
3170
|
runReviewPipeline: () => runReviewPipeline,
|
|
3138
3171
|
runSecurityAgent: () => runSecurityAgent,
|
|
3139
3172
|
saveHandoff: () => saveHandoff,
|
|
@@ -3145,6 +3178,7 @@ __export(dist_exports, {
|
|
|
3145
3178
|
searchSymbols: () => searchSymbols,
|
|
3146
3179
|
secretRules: () => secretRules,
|
|
3147
3180
|
securityFindingId: () => securityFindingId,
|
|
3181
|
+
seedFromStrategy: () => seedFromStrategy,
|
|
3148
3182
|
send: () => send,
|
|
3149
3183
|
serializeEnvelope: () => serializeEnvelope,
|
|
3150
3184
|
serializeRoadmap: () => serializeRoadmap,
|
|
@@ -3154,6 +3188,7 @@ __export(dist_exports, {
|
|
|
3154
3188
|
spawnBackgroundCheck: () => spawnBackgroundCheck,
|
|
3155
3189
|
splitBundlesByStage: () => splitBundlesByStage,
|
|
3156
3190
|
stageDomains: () => stageDomains,
|
|
3191
|
+
suggestCategory: () => suggestCategory,
|
|
3157
3192
|
syncConstraintNodes: () => syncConstraintNodes,
|
|
3158
3193
|
syncFromExternal: () => syncFromExternal,
|
|
3159
3194
|
syncRoadmap: () => syncRoadmap,
|
|
@@ -3176,164 +3211,188 @@ __export(dist_exports, {
|
|
|
3176
3211
|
validateFindings: () => validateFindings,
|
|
3177
3212
|
validateKnowledgeMap: () => validateKnowledgeMap,
|
|
3178
3213
|
validatePatternConfig: () => validatePatternConfig,
|
|
3214
|
+
validatePulseConfig: () => validatePulseConfig,
|
|
3215
|
+
validateSolutionsDir: () => validateSolutionsDir,
|
|
3179
3216
|
violationId: () => violationId,
|
|
3180
3217
|
weeksUntilThreshold: () => weeksUntilThreshold,
|
|
3181
3218
|
weightedLinearRegression: () => weightedLinearRegression,
|
|
3182
3219
|
writeConfig: () => writeConfig,
|
|
3183
3220
|
writeLockfile: () => writeLockfile,
|
|
3221
|
+
writePulseConfig: () => writePulseConfig,
|
|
3184
3222
|
writeSessionSummary: () => writeSessionSummary,
|
|
3185
3223
|
writeTaint: () => writeTaint,
|
|
3186
3224
|
xssRules: () => xssRules
|
|
3187
3225
|
});
|
|
3226
|
+
import * as fs from "fs/promises";
|
|
3227
|
+
import * as path from "path";
|
|
3228
|
+
import { z as z2 } from "zod";
|
|
3229
|
+
import * as fs2 from "fs/promises";
|
|
3230
|
+
import * as path2 from "path";
|
|
3231
|
+
import matter from "gray-matter";
|
|
3232
|
+
import { z as z22 } from "zod";
|
|
3188
3233
|
import { spawn } from "child_process";
|
|
3189
3234
|
import { existsSync as existsSync2 } from "fs";
|
|
3190
|
-
import { join as
|
|
3235
|
+
import { join as join32, isAbsolute } from "path";
|
|
3191
3236
|
import { existsSync as existsSync22 } from "fs";
|
|
3192
|
-
import { join as
|
|
3237
|
+
import { join as join42 } from "path";
|
|
3193
3238
|
import { readFileSync as readFileSync2, statSync } from "fs";
|
|
3194
3239
|
import { glob as glob2 } from "glob";
|
|
3195
3240
|
import { existsSync as existsSync3 } from "fs";
|
|
3196
|
-
import { isAbsolute as isAbsolute2, resolve as resolve3, join as
|
|
3241
|
+
import { isAbsolute as isAbsolute2, resolve as resolve3, join as join52 } from "path";
|
|
3197
3242
|
import { glob as glob22 } from "glob";
|
|
3198
3243
|
import { existsSync as existsSync4 } from "fs";
|
|
3199
|
-
import { basename, dirname as dirname4, join as
|
|
3244
|
+
import { basename, dirname as dirname4, join as join6 } from "path";
|
|
3200
3245
|
import { existsSync as existsSync5 } from "fs";
|
|
3201
|
-
import { join as join5 } from "path";
|
|
3202
|
-
import { existsSync as existsSync6 } from "fs";
|
|
3203
3246
|
import { join as join7 } from "path";
|
|
3204
|
-
import {
|
|
3247
|
+
import { existsSync as existsSync6 } from "fs";
|
|
3248
|
+
import { join as join9 } from "path";
|
|
3249
|
+
import { join as join8, dirname as dirname22 } from "path";
|
|
3205
3250
|
import { glob as glob3 } from "glob";
|
|
3206
3251
|
import { existsSync as existsSync7 } from "fs";
|
|
3207
3252
|
import { dirname as dirname32, resolve as resolve22, isAbsolute as isAbsolute3 } from "path";
|
|
3208
3253
|
import { existsSync as existsSync8 } from "fs";
|
|
3209
|
-
import { join as
|
|
3254
|
+
import { join as join10 } from "path";
|
|
3210
3255
|
import { glob as glob4 } from "glob";
|
|
3211
3256
|
import { existsSync as existsSync9 } from "fs";
|
|
3212
|
-
import { join as
|
|
3257
|
+
import { join as join11 } from "path";
|
|
3213
3258
|
import { existsSync as existsSync10 } from "fs";
|
|
3214
|
-
import { join as
|
|
3259
|
+
import { join as join12 } from "path";
|
|
3215
3260
|
import { minimatch as minimatch2 } from "minimatch";
|
|
3216
3261
|
import { basename as basename2 } from "path";
|
|
3217
|
-
import { join as
|
|
3262
|
+
import { join as join13, basename as basename3 } from "path";
|
|
3218
3263
|
import { basename as basename4, dirname as dirname42 } from "path";
|
|
3219
|
-
import { z as
|
|
3220
|
-
import * as
|
|
3221
|
-
import * as
|
|
3222
|
-
import { join as
|
|
3264
|
+
import { z as z3 } from "zod";
|
|
3265
|
+
import * as fs3 from "fs/promises";
|
|
3266
|
+
import * as fs4 from "fs/promises";
|
|
3267
|
+
import { join as join14, resolve as resolve32 } from "path";
|
|
3223
3268
|
import { minimatch as minimatch22 } from "minimatch";
|
|
3224
3269
|
import { dirname as dirname5, resolve as resolve4 } from "path";
|
|
3225
3270
|
import { dirname as dirname6, resolve as resolve5 } from "path";
|
|
3226
3271
|
import { minimatch as minimatch3 } from "minimatch";
|
|
3227
3272
|
import { readdirSync, statSync as statSync2 } from "fs";
|
|
3228
|
-
import { join as
|
|
3229
|
-
import * as
|
|
3273
|
+
import { join as join15 } from "path";
|
|
3274
|
+
import * as fs5 from "fs";
|
|
3230
3275
|
import { promisify as promisify2 } from "util";
|
|
3231
|
-
import { dirname as dirname7, basename as basename5, join as
|
|
3232
|
-
import { z as
|
|
3276
|
+
import { dirname as dirname7, basename as basename5, join as join16 } from "path";
|
|
3277
|
+
import { z as z4 } from "zod";
|
|
3233
3278
|
import { readFileSync as readFileSync22, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync11 } from "fs";
|
|
3234
|
-
import { join as
|
|
3279
|
+
import { join as join17, dirname as dirname8 } from "path";
|
|
3235
3280
|
import { execFileSync } from "child_process";
|
|
3236
|
-
import * as
|
|
3237
|
-
import * as
|
|
3281
|
+
import * as fs6 from "fs";
|
|
3282
|
+
import * as path3 from "path";
|
|
3238
3283
|
import { appendFileSync, writeFileSync as writeFileSync22, existsSync as existsSync12, mkdirSync as mkdirSync22 } from "fs";
|
|
3239
3284
|
import { dirname as dirname9 } from "path";
|
|
3240
|
-
import { z as
|
|
3285
|
+
import { z as z5 } from "zod";
|
|
3241
3286
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, mkdirSync as mkdirSync3, existsSync as existsSync13 } from "fs";
|
|
3242
3287
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3243
|
-
import { join as
|
|
3244
|
-
import { z as
|
|
3245
|
-
import * as fs5 from "fs";
|
|
3246
|
-
import * as path2 from "path";
|
|
3247
|
-
import * as fs6 from "fs";
|
|
3248
|
-
import * as path3 from "path";
|
|
3288
|
+
import { join as join19, dirname as dirname10 } from "path";
|
|
3289
|
+
import { z as z6 } from "zod";
|
|
3249
3290
|
import * as fs7 from "fs";
|
|
3250
3291
|
import * as path4 from "path";
|
|
3251
|
-
import { z as z5 } from "zod";
|
|
3252
|
-
import * as fs11 from "fs";
|
|
3253
|
-
import * as path8 from "path";
|
|
3254
|
-
import * as fs10 from "fs";
|
|
3255
|
-
import * as path7 from "path";
|
|
3256
3292
|
import * as fs8 from "fs";
|
|
3257
3293
|
import * as path5 from "path";
|
|
3258
|
-
import { execSync } from "child_process";
|
|
3259
|
-
import { z as z6 } from "zod";
|
|
3260
3294
|
import * as fs9 from "fs";
|
|
3261
3295
|
import * as path6 from "path";
|
|
3262
|
-
import
|
|
3263
|
-
import * as path9 from "path";
|
|
3264
|
-
import * as crypto2 from "crypto";
|
|
3296
|
+
import { z as z7 } from "zod";
|
|
3265
3297
|
import * as fs13 from "fs";
|
|
3266
3298
|
import * as path10 from "path";
|
|
3299
|
+
import * as fs12 from "fs";
|
|
3300
|
+
import * as path9 from "path";
|
|
3301
|
+
import * as fs10 from "fs";
|
|
3302
|
+
import * as path7 from "path";
|
|
3303
|
+
import { execSync } from "child_process";
|
|
3304
|
+
import { z as z8 } from "zod";
|
|
3305
|
+
import * as fs11 from "fs";
|
|
3306
|
+
import * as path8 from "path";
|
|
3267
3307
|
import * as fs14 from "fs";
|
|
3268
3308
|
import * as path11 from "path";
|
|
3269
|
-
import * as
|
|
3309
|
+
import * as crypto2 from "crypto";
|
|
3270
3310
|
import * as fs15 from "fs";
|
|
3271
3311
|
import * as path12 from "path";
|
|
3272
3312
|
import * as fs16 from "fs";
|
|
3273
3313
|
import * as path13 from "path";
|
|
3314
|
+
import * as crypto3 from "crypto";
|
|
3274
3315
|
import * as fs17 from "fs";
|
|
3275
3316
|
import * as path14 from "path";
|
|
3276
3317
|
import * as fs18 from "fs";
|
|
3277
3318
|
import * as path15 from "path";
|
|
3278
3319
|
import * as fs19 from "fs";
|
|
3279
3320
|
import * as path16 from "path";
|
|
3280
|
-
import { execSync as execSync2 } from "child_process";
|
|
3281
3321
|
import * as fs20 from "fs";
|
|
3282
3322
|
import * as path17 from "path";
|
|
3283
3323
|
import * as fs21 from "fs";
|
|
3284
3324
|
import * as path18 from "path";
|
|
3325
|
+
import { execSync as execSync2 } from "child_process";
|
|
3285
3326
|
import * as fs22 from "fs";
|
|
3286
3327
|
import * as path19 from "path";
|
|
3287
3328
|
import * as fs23 from "fs";
|
|
3288
3329
|
import * as path20 from "path";
|
|
3289
|
-
import { z as z7 } from "zod";
|
|
3290
|
-
import * as fs25 from "fs/promises";
|
|
3291
|
-
import { minimatch as minimatch4 } from "minimatch";
|
|
3292
|
-
import { z as z8 } from "zod";
|
|
3293
3330
|
import * as fs24 from "fs";
|
|
3294
3331
|
import * as path21 from "path";
|
|
3332
|
+
import * as fs25 from "fs";
|
|
3333
|
+
import * as path22 from "path";
|
|
3334
|
+
import { z as z9 } from "zod";
|
|
3335
|
+
import * as fs27 from "fs/promises";
|
|
3336
|
+
import { minimatch as minimatch4 } from "minimatch";
|
|
3337
|
+
import { z as z10 } from "zod";
|
|
3338
|
+
import * as fs26 from "fs";
|
|
3339
|
+
import * as path23 from "path";
|
|
3295
3340
|
import { readFileSync as readFileSync222, writeFileSync as writeFileSync15, unlinkSync as unlinkSync2, mkdirSync as mkdirSync14, readdirSync as readdirSync3 } from "fs";
|
|
3296
|
-
import { join as
|
|
3341
|
+
import { join as join382, dirname as dirname12 } from "path";
|
|
3297
3342
|
import { createHash as createHash32 } from "crypto";
|
|
3298
|
-
import { z as
|
|
3343
|
+
import { z as z11 } from "zod";
|
|
3299
3344
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync16, renameSync as renameSync82, mkdirSync as mkdirSync15, existsSync as existsSync332 } from "fs";
|
|
3300
3345
|
import { execSync as execSync3 } from "child_process";
|
|
3301
3346
|
import { randomBytes as randomBytes22 } from "crypto";
|
|
3302
|
-
import { join as
|
|
3303
|
-
import * as path22 from "path";
|
|
3304
|
-
import * as path23 from "path";
|
|
3347
|
+
import { join as join39, dirname as dirname13 } from "path";
|
|
3305
3348
|
import * as path24 from "path";
|
|
3306
3349
|
import * as path25 from "path";
|
|
3307
|
-
import * as fs26 from "fs";
|
|
3308
3350
|
import * as path26 from "path";
|
|
3309
|
-
import * as fs27 from "fs";
|
|
3310
3351
|
import * as path27 from "path";
|
|
3311
3352
|
import * as fs28 from "fs";
|
|
3312
|
-
import { z as z10 } from "zod";
|
|
3313
|
-
import * as fs29 from "fs/promises";
|
|
3314
3353
|
import * as path28 from "path";
|
|
3315
|
-
import * as
|
|
3354
|
+
import * as fs29 from "fs";
|
|
3316
3355
|
import * as path29 from "path";
|
|
3317
|
-
import * as
|
|
3318
|
-
import
|
|
3356
|
+
import * as fs30 from "fs";
|
|
3357
|
+
import { z as z12 } from "zod";
|
|
3358
|
+
import * as fs31 from "fs/promises";
|
|
3319
3359
|
import * as path30 from "path";
|
|
3320
|
-
import * as os from "os";
|
|
3321
|
-
import { spawn as spawn2 } from "child_process";
|
|
3322
3360
|
import * as fs32 from "fs/promises";
|
|
3323
3361
|
import * as path31 from "path";
|
|
3362
|
+
import * as ejs from "ejs";
|
|
3324
3363
|
import * as fs33 from "fs";
|
|
3325
3364
|
import * as path32 from "path";
|
|
3326
|
-
import * as
|
|
3365
|
+
import * as os from "os";
|
|
3366
|
+
import { spawn as spawn2 } from "child_process";
|
|
3367
|
+
import * as fs34 from "fs/promises";
|
|
3327
3368
|
import * as path33 from "path";
|
|
3328
|
-
import * as os2 from "os";
|
|
3329
3369
|
import * as fs35 from "fs";
|
|
3330
3370
|
import * as path34 from "path";
|
|
3371
|
+
import * as fs36 from "fs";
|
|
3372
|
+
import * as path35 from "path";
|
|
3373
|
+
import * as os2 from "os";
|
|
3331
3374
|
import * as fs37 from "fs";
|
|
3332
3375
|
import * as path36 from "path";
|
|
3376
|
+
import * as fs39 from "fs";
|
|
3377
|
+
import * as path38 from "path";
|
|
3333
3378
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
3334
|
-
import * as
|
|
3335
|
-
import * as
|
|
3379
|
+
import * as fs38 from "fs";
|
|
3380
|
+
import * as path37 from "path";
|
|
3336
3381
|
import * as crypto4 from "crypto";
|
|
3382
|
+
import * as fs40 from "fs";
|
|
3383
|
+
import * as path39 from "path";
|
|
3384
|
+
import * as fs41 from "fs";
|
|
3385
|
+
import * as fs42 from "fs";
|
|
3386
|
+
import * as path40 from "path";
|
|
3387
|
+
import { readFileSync as readFileSync36 } from "fs";
|
|
3388
|
+
import { fileURLToPath } from "url";
|
|
3389
|
+
import { dirname as dirname18, join as join572 } from "path";
|
|
3390
|
+
import { execFile } from "child_process";
|
|
3391
|
+
import { promisify as promisify22 } from "util";
|
|
3392
|
+
import { execFile as execFile2 } from "child_process";
|
|
3393
|
+
import { promisify as promisify3 } from "util";
|
|
3394
|
+
import * as fs43 from "fs/promises";
|
|
3395
|
+
import * as path41 from "path";
|
|
3337
3396
|
async function validateFileStructure(projectPath, conventions) {
|
|
3338
3397
|
const missing = [];
|
|
3339
3398
|
const unexpected = [];
|
|
@@ -3369,15 +3428,15 @@ function validateConfig(data, schema) {
|
|
|
3369
3428
|
let message = "Configuration validation failed";
|
|
3370
3429
|
const suggestions = [];
|
|
3371
3430
|
if (firstError) {
|
|
3372
|
-
const
|
|
3373
|
-
const pathDisplay =
|
|
3431
|
+
const path42 = firstError.path.join(".");
|
|
3432
|
+
const pathDisplay = path42 ? ` at "${path42}"` : "";
|
|
3374
3433
|
if (firstError.code === "invalid_type") {
|
|
3375
3434
|
const received = firstError.received;
|
|
3376
3435
|
const expected = firstError.expected;
|
|
3377
3436
|
if (received === "undefined") {
|
|
3378
3437
|
code = "MISSING_FIELD";
|
|
3379
3438
|
message = `Missing required field${pathDisplay}: ${firstError.message}`;
|
|
3380
|
-
suggestions.push(`Field "${
|
|
3439
|
+
suggestions.push(`Field "${path42}" is required and must be of type "${expected}"`);
|
|
3381
3440
|
} else {
|
|
3382
3441
|
code = "INVALID_TYPE";
|
|
3383
3442
|
message = `Invalid type${pathDisplay}: ${firstError.message}`;
|
|
@@ -3487,6 +3546,82 @@ function validateConventionalCommit(message) {
|
|
|
3487
3546
|
issues: []
|
|
3488
3547
|
});
|
|
3489
3548
|
}
|
|
3549
|
+
async function validatePulseConfig(cwd) {
|
|
3550
|
+
const configPath = path.join(cwd, "harness.config.json");
|
|
3551
|
+
let raw;
|
|
3552
|
+
try {
|
|
3553
|
+
raw = await fs.readFile(configPath, "utf-8");
|
|
3554
|
+
} catch {
|
|
3555
|
+
return Ok({ present: false, valid: true });
|
|
3556
|
+
}
|
|
3557
|
+
let parsed;
|
|
3558
|
+
try {
|
|
3559
|
+
parsed = JSON.parse(raw);
|
|
3560
|
+
} catch (e) {
|
|
3561
|
+
return Err(
|
|
3562
|
+
createError(
|
|
3563
|
+
"VALIDATION_FAILED",
|
|
3564
|
+
`harness.config.json is not valid JSON: ${e.message}`,
|
|
3565
|
+
{},
|
|
3566
|
+
[]
|
|
3567
|
+
)
|
|
3568
|
+
);
|
|
3569
|
+
}
|
|
3570
|
+
if (!("pulse" in parsed)) return Ok({ present: false, valid: true });
|
|
3571
|
+
const result = validateConfig(parsed.pulse, PulseConfigSchema);
|
|
3572
|
+
if (!result.ok) return Err(result.error);
|
|
3573
|
+
return Ok({ present: true, valid: true });
|
|
3574
|
+
}
|
|
3575
|
+
async function* walk2(dir) {
|
|
3576
|
+
let entries;
|
|
3577
|
+
try {
|
|
3578
|
+
entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
3579
|
+
} catch {
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
for (const e of entries) {
|
|
3583
|
+
const p = path2.join(dir, e.name);
|
|
3584
|
+
if (e.isDirectory()) yield* walk2(p);
|
|
3585
|
+
else if (e.isFile() && e.name.endsWith(".md")) yield p;
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
async function validateSolutionsDir(cwd) {
|
|
3589
|
+
const root = path2.join(cwd, "docs", "solutions");
|
|
3590
|
+
try {
|
|
3591
|
+
await fs2.stat(root);
|
|
3592
|
+
} catch {
|
|
3593
|
+
return Ok({ filesChecked: 0, issues: [] });
|
|
3594
|
+
}
|
|
3595
|
+
const issues = [];
|
|
3596
|
+
let count = 0;
|
|
3597
|
+
for (const [track, categories] of TRACK_CATEGORIES) {
|
|
3598
|
+
for (const category of categories) {
|
|
3599
|
+
const categoryDir = path2.join(root, track, category);
|
|
3600
|
+
for await (const file of walk2(categoryDir)) {
|
|
3601
|
+
count++;
|
|
3602
|
+
const raw = await fs2.readFile(file, "utf-8");
|
|
3603
|
+
const parsed = matter(raw);
|
|
3604
|
+
const result = validateConfig(parsed.data, SolutionDocFrontmatterSchema);
|
|
3605
|
+
if (!result.ok)
|
|
3606
|
+
issues.push({
|
|
3607
|
+
file: path2.relative(cwd, file).replaceAll("\\", "/"),
|
|
3608
|
+
message: result.error.message
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
if (issues.length > 0) {
|
|
3614
|
+
return Err(
|
|
3615
|
+
createError(
|
|
3616
|
+
"VALIDATION_FAILED",
|
|
3617
|
+
`${issues.length} solution doc(s) failed frontmatter validation`,
|
|
3618
|
+
{ issues },
|
|
3619
|
+
[]
|
|
3620
|
+
)
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
3623
|
+
return Ok({ filesChecked: count, issues: [] });
|
|
3624
|
+
}
|
|
3490
3625
|
function resolveAgnixBinary(explicit) {
|
|
3491
3626
|
if (explicit) return existsSync2(explicit) ? explicit : null;
|
|
3492
3627
|
const fromEnv = process.env[HARNESS_AGNIX_BIN];
|
|
@@ -3507,7 +3642,7 @@ function lookupOnPath() {
|
|
|
3507
3642
|
function firstExistingIn(dir, candidates) {
|
|
3508
3643
|
if (!dir) return null;
|
|
3509
3644
|
for (const name of candidates) {
|
|
3510
|
-
const candidate = isAbsolute(dir) ?
|
|
3645
|
+
const candidate = isAbsolute(dir) ? join32(dir, name) : join32(process.cwd(), dir, name);
|
|
3511
3646
|
if (existsSync2(candidate)) return candidate;
|
|
3512
3647
|
}
|
|
3513
3648
|
return null;
|
|
@@ -3584,7 +3719,7 @@ function extractDiagnostics(parsed) {
|
|
|
3584
3719
|
}
|
|
3585
3720
|
function normalizeDiagnostic(diag, cwd) {
|
|
3586
3721
|
const finding = {
|
|
3587
|
-
file: normalizeFilePath(
|
|
3722
|
+
file: normalizeFilePath(readFile32(diag), cwd),
|
|
3588
3723
|
ruleId: readRuleId(diag),
|
|
3589
3724
|
severity: normalizeSeverity(readSeverity(diag)),
|
|
3590
3725
|
message: diag.message ?? "agnix diagnostic"
|
|
@@ -3592,7 +3727,7 @@ function normalizeDiagnostic(diag, cwd) {
|
|
|
3592
3727
|
attachOptionalFields(finding, diag);
|
|
3593
3728
|
return finding;
|
|
3594
3729
|
}
|
|
3595
|
-
function
|
|
3730
|
+
function readFile32(diag) {
|
|
3596
3731
|
return diag.file ?? diag.path ?? "";
|
|
3597
3732
|
}
|
|
3598
3733
|
function readRuleId(diag) {
|
|
@@ -3635,16 +3770,16 @@ function makeFinding(input) {
|
|
|
3635
3770
|
if (input.suggestion) finding.suggestion = input.suggestion;
|
|
3636
3771
|
return finding;
|
|
3637
3772
|
}
|
|
3638
|
-
function readTextSafe(
|
|
3773
|
+
function readTextSafe(path42) {
|
|
3639
3774
|
try {
|
|
3640
|
-
return readFileSync2(
|
|
3775
|
+
return readFileSync2(path42, "utf-8");
|
|
3641
3776
|
} catch {
|
|
3642
3777
|
return null;
|
|
3643
3778
|
}
|
|
3644
3779
|
}
|
|
3645
|
-
function safeFileSize(
|
|
3780
|
+
function safeFileSize(path42) {
|
|
3646
3781
|
try {
|
|
3647
|
-
return statSync(
|
|
3782
|
+
return statSync(path42).size;
|
|
3648
3783
|
} catch {
|
|
3649
3784
|
return null;
|
|
3650
3785
|
}
|
|
@@ -3681,7 +3816,7 @@ function stripQuotes(value) {
|
|
|
3681
3816
|
function runClaudeMdRules(cwd) {
|
|
3682
3817
|
const findings = [];
|
|
3683
3818
|
for (const name of CONTEXT_FILES) {
|
|
3684
|
-
const abs =
|
|
3819
|
+
const abs = join42(cwd, name);
|
|
3685
3820
|
if (!existsSync22(abs)) continue;
|
|
3686
3821
|
findings.push(...inspectContextFile(abs, name));
|
|
3687
3822
|
}
|
|
@@ -3828,7 +3963,7 @@ function appendDescriptionFindings(out, rel, description) {
|
|
|
3828
3963
|
function runHookRules(cwd) {
|
|
3829
3964
|
const findings = [];
|
|
3830
3965
|
for (const rel of SETTINGS_PATHS) {
|
|
3831
|
-
const abs =
|
|
3966
|
+
const abs = join52(cwd, rel);
|
|
3832
3967
|
if (!existsSync3(abs)) continue;
|
|
3833
3968
|
const content = readTextSafe(abs);
|
|
3834
3969
|
if (content === null) continue;
|
|
@@ -3944,7 +4079,7 @@ async function runSkillRules(cwd) {
|
|
|
3944
4079
|
for (const abs of skillFiles) {
|
|
3945
4080
|
const rel = relPath(cwd, abs);
|
|
3946
4081
|
const dirName = basename(dirname4(abs));
|
|
3947
|
-
const siblingYaml =
|
|
4082
|
+
const siblingYaml = join6(dirname4(abs), "skill.yaml");
|
|
3948
4083
|
if (existsSync4(siblingYaml)) {
|
|
3949
4084
|
const yamlFields = parseFrontmatterFields(readTextSafe(siblingYaml) ?? "");
|
|
3950
4085
|
findings.push(...checkSkillMetadata(relPath(cwd, siblingYaml), dirName, yamlFields));
|
|
@@ -4050,7 +4185,7 @@ function runMcpRules(cwd) {
|
|
|
4050
4185
|
return findings;
|
|
4051
4186
|
}
|
|
4052
4187
|
function loadMcpServers(cwd, rel) {
|
|
4053
|
-
const abs =
|
|
4188
|
+
const abs = join7(cwd, rel);
|
|
4054
4189
|
if (!existsSync5(abs)) return null;
|
|
4055
4190
|
const content = readTextSafe(abs);
|
|
4056
4191
|
if (content === null) return null;
|
|
@@ -4189,27 +4324,27 @@ function extractSections(content) {
|
|
|
4189
4324
|
}
|
|
4190
4325
|
return sections.map((section) => buildAgentMapSection(section, lines));
|
|
4191
4326
|
}
|
|
4192
|
-
function isExternalLink(
|
|
4193
|
-
return
|
|
4327
|
+
function isExternalLink(path42) {
|
|
4328
|
+
return path42.startsWith("http://") || path42.startsWith("https://") || path42.startsWith("#") || path42.startsWith("mailto:");
|
|
4194
4329
|
}
|
|
4195
4330
|
function resolveLinkPath(linkPath, baseDir) {
|
|
4196
|
-
return linkPath.startsWith(".") ?
|
|
4331
|
+
return linkPath.startsWith(".") ? join8(baseDir, linkPath) : linkPath;
|
|
4197
4332
|
}
|
|
4198
|
-
async function validateAgentsMap(
|
|
4199
|
-
const contentResult = await readFileContent(
|
|
4333
|
+
async function validateAgentsMap(path42 = "./AGENTS.md") {
|
|
4334
|
+
const contentResult = await readFileContent(path42);
|
|
4200
4335
|
if (!contentResult.ok) {
|
|
4201
4336
|
return Err(
|
|
4202
4337
|
createError(
|
|
4203
4338
|
"PARSE_ERROR",
|
|
4204
4339
|
`Failed to read AGENTS.md: ${contentResult.error.message}`,
|
|
4205
|
-
{ path:
|
|
4340
|
+
{ path: path42 },
|
|
4206
4341
|
["Ensure the file exists", "Check file permissions"]
|
|
4207
4342
|
)
|
|
4208
4343
|
);
|
|
4209
4344
|
}
|
|
4210
4345
|
const content = contentResult.value;
|
|
4211
4346
|
const sections = extractSections(content);
|
|
4212
|
-
const baseDir = dirname22(
|
|
4347
|
+
const baseDir = dirname22(path42);
|
|
4213
4348
|
const sectionTitles = sections.map((s) => s.title);
|
|
4214
4349
|
const missingSections = REQUIRED_SECTIONS.filter(
|
|
4215
4350
|
(required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
|
|
@@ -4248,7 +4383,7 @@ async function validateAgentsMap(path37 = "./AGENTS.md") {
|
|
|
4248
4383
|
});
|
|
4249
4384
|
}
|
|
4250
4385
|
async function runAgentsMdRules(cwd) {
|
|
4251
|
-
const abs =
|
|
4386
|
+
const abs = join9(cwd, "AGENTS.md");
|
|
4252
4387
|
if (!existsSync6(abs)) return [];
|
|
4253
4388
|
const result = await validateAgentsMap(abs);
|
|
4254
4389
|
if (result.ok) return [];
|
|
@@ -4305,7 +4440,7 @@ function extractLinkTargets(content) {
|
|
|
4305
4440
|
function runSettingsJsonRules(cwd) {
|
|
4306
4441
|
const findings = [];
|
|
4307
4442
|
for (const rel of SETTINGS_FILES) {
|
|
4308
|
-
const abs =
|
|
4443
|
+
const abs = join10(cwd, rel);
|
|
4309
4444
|
if (!existsSync8(abs)) continue;
|
|
4310
4445
|
const content = readTextSafe(abs);
|
|
4311
4446
|
if (content === null) continue;
|
|
@@ -4381,15 +4516,15 @@ function stripQuotes2(value) {
|
|
|
4381
4516
|
return value;
|
|
4382
4517
|
}
|
|
4383
4518
|
function skillExists(cwd, slug) {
|
|
4384
|
-
if (existsSync9(
|
|
4519
|
+
if (existsSync9(join11(cwd, "agents", "skills", slug, "SKILL.md"))) return true;
|
|
4385
4520
|
for (const platform of ["claude-code", "gemini-cli", "codex", "cursor", "shared"]) {
|
|
4386
|
-
if (existsSync9(
|
|
4521
|
+
if (existsSync9(join11(cwd, "agents", "skills", platform, slug, "SKILL.md"))) return true;
|
|
4387
4522
|
}
|
|
4388
4523
|
return false;
|
|
4389
4524
|
}
|
|
4390
4525
|
function runAgnixTomlRules(cwd) {
|
|
4391
4526
|
const rel = ".agnix.toml";
|
|
4392
|
-
const abs =
|
|
4527
|
+
const abs = join12(cwd, rel);
|
|
4393
4528
|
if (!existsSync10(abs)) return [];
|
|
4394
4529
|
const content = readTextSafe(abs);
|
|
4395
4530
|
if (content === null) return [];
|
|
@@ -4649,8 +4784,8 @@ async function checkDocCoverage(domain, options = {}) {
|
|
|
4649
4784
|
);
|
|
4650
4785
|
}
|
|
4651
4786
|
}
|
|
4652
|
-
function suggestFix(
|
|
4653
|
-
const targetName = basename3(
|
|
4787
|
+
function suggestFix(path42, existingFiles) {
|
|
4788
|
+
const targetName = basename3(path42).toLowerCase();
|
|
4654
4789
|
const similar = existingFiles.find((file) => {
|
|
4655
4790
|
const fileName = basename3(file).toLowerCase();
|
|
4656
4791
|
return fileName.includes(targetName) || targetName.includes(fileName);
|
|
@@ -4658,10 +4793,10 @@ function suggestFix(path37, existingFiles) {
|
|
|
4658
4793
|
if (similar) {
|
|
4659
4794
|
return `Did you mean "${similar}"?`;
|
|
4660
4795
|
}
|
|
4661
|
-
return `Create the file "${
|
|
4796
|
+
return `Create the file "${path42}" or remove the link`;
|
|
4662
4797
|
}
|
|
4663
4798
|
async function validateKnowledgeMap(rootDir = process.cwd()) {
|
|
4664
|
-
const agentsPath =
|
|
4799
|
+
const agentsPath = join13(rootDir, "AGENTS.md");
|
|
4665
4800
|
const agentsResult = await validateAgentsMap(agentsPath);
|
|
4666
4801
|
if (!agentsResult.ok) {
|
|
4667
4802
|
return Err(agentsResult.error);
|
|
@@ -5016,8 +5151,8 @@ function createBoundaryValidator(schema, name) {
|
|
|
5016
5151
|
return Ok(result.data);
|
|
5017
5152
|
}
|
|
5018
5153
|
const suggestions = result.error.issues.map((issue) => {
|
|
5019
|
-
const
|
|
5020
|
-
return
|
|
5154
|
+
const path42 = issue.path.join(".");
|
|
5155
|
+
return path42 ? `${path42}: ${issue.message}` : issue.message;
|
|
5021
5156
|
});
|
|
5022
5157
|
return Err(
|
|
5023
5158
|
createError(
|
|
@@ -5063,7 +5198,7 @@ function validateBoundaries(boundaries, data) {
|
|
|
5063
5198
|
async function writeConfig(filePath, content) {
|
|
5064
5199
|
try {
|
|
5065
5200
|
const json = JSON.stringify(content, null, 2) + "\n";
|
|
5066
|
-
await
|
|
5201
|
+
await fs3.writeFile(filePath, json, "utf-8");
|
|
5067
5202
|
return Ok(void 0);
|
|
5068
5203
|
} catch (error) {
|
|
5069
5204
|
return Err(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -5337,7 +5472,7 @@ function deepMergeConstraints(localConfig, bundleConstraints, _existingContribut
|
|
|
5337
5472
|
async function readLockfile(lockfilePath) {
|
|
5338
5473
|
let raw;
|
|
5339
5474
|
try {
|
|
5340
|
-
raw = await
|
|
5475
|
+
raw = await fs4.readFile(lockfilePath, "utf-8");
|
|
5341
5476
|
} catch (err) {
|
|
5342
5477
|
if (isNodeError(err) && err.code === "ENOENT") {
|
|
5343
5478
|
return { ok: true, value: null };
|
|
@@ -5640,7 +5775,7 @@ async function resolveEntryPoints(rootDir, explicitEntries) {
|
|
|
5640
5775
|
if (explicitEntries && explicitEntries.length > 0) {
|
|
5641
5776
|
return Ok(explicitEntries.map((e) => resolve32(rootDir, e)));
|
|
5642
5777
|
}
|
|
5643
|
-
const pkgPath =
|
|
5778
|
+
const pkgPath = join14(rootDir, "package.json");
|
|
5644
5779
|
if (await fileExists(pkgPath)) {
|
|
5645
5780
|
const pkgContent = await readFileContent(pkgPath);
|
|
5646
5781
|
if (pkgContent.ok) {
|
|
@@ -5654,7 +5789,7 @@ async function resolveEntryPoints(rootDir, explicitEntries) {
|
|
|
5654
5789
|
}
|
|
5655
5790
|
const conventions = ["src/index.ts", "src/main.ts", "index.ts", "main.ts"];
|
|
5656
5791
|
for (const conv of conventions) {
|
|
5657
|
-
const convPath =
|
|
5792
|
+
const convPath = join14(rootDir, conv);
|
|
5658
5793
|
if (await fileExists(convPath)) {
|
|
5659
5794
|
return Ok([convPath]);
|
|
5660
5795
|
}
|
|
@@ -5721,22 +5856,22 @@ function extractInlineRefs(content) {
|
|
|
5721
5856
|
}
|
|
5722
5857
|
return refs;
|
|
5723
5858
|
}
|
|
5724
|
-
async function parseDocumentationFile(
|
|
5725
|
-
const contentResult = await readFileContent(
|
|
5859
|
+
async function parseDocumentationFile(path42) {
|
|
5860
|
+
const contentResult = await readFileContent(path42);
|
|
5726
5861
|
if (!contentResult.ok) {
|
|
5727
5862
|
return Err(
|
|
5728
5863
|
createEntropyError(
|
|
5729
5864
|
"PARSE_ERROR",
|
|
5730
|
-
`Failed to read documentation file: ${
|
|
5731
|
-
{ file:
|
|
5865
|
+
`Failed to read documentation file: ${path42}`,
|
|
5866
|
+
{ file: path42 },
|
|
5732
5867
|
["Check that the file exists"]
|
|
5733
5868
|
)
|
|
5734
5869
|
);
|
|
5735
5870
|
}
|
|
5736
5871
|
const content = contentResult.value;
|
|
5737
|
-
const type =
|
|
5872
|
+
const type = path42.endsWith(".md") ? "markdown" : "text";
|
|
5738
5873
|
return Ok({
|
|
5739
|
-
path:
|
|
5874
|
+
path: path42,
|
|
5740
5875
|
type,
|
|
5741
5876
|
content,
|
|
5742
5877
|
codeBlocks: extractCodeBlocks(content),
|
|
@@ -6635,13 +6770,13 @@ function dirSize(dirPath) {
|
|
|
6635
6770
|
}
|
|
6636
6771
|
for (const entry of entries) {
|
|
6637
6772
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
6638
|
-
const fullPath =
|
|
6773
|
+
const fullPath = join15(dirPath, entry);
|
|
6639
6774
|
try {
|
|
6640
|
-
const
|
|
6641
|
-
if (
|
|
6775
|
+
const stat2 = statSync2(fullPath);
|
|
6776
|
+
if (stat2.isDirectory()) {
|
|
6642
6777
|
total += dirSize(fullPath);
|
|
6643
|
-
} else if (
|
|
6644
|
-
total +=
|
|
6778
|
+
} else if (stat2.isFile()) {
|
|
6779
|
+
total += stat2.size;
|
|
6645
6780
|
}
|
|
6646
6781
|
} catch {
|
|
6647
6782
|
continue;
|
|
@@ -6655,7 +6790,7 @@ async function detectSizeBudgetViolations(rootDir, config) {
|
|
|
6655
6790
|
let packagesChecked = 0;
|
|
6656
6791
|
for (const [pkgPath, budget] of Object.entries(budgets)) {
|
|
6657
6792
|
packagesChecked++;
|
|
6658
|
-
const distPath =
|
|
6793
|
+
const distPath = join15(rootDir, pkgPath, "dist");
|
|
6659
6794
|
const currentSize = dirSize(distPath);
|
|
6660
6795
|
if (budget.warn) {
|
|
6661
6796
|
const budgetBytes = parseSize(budget.warn);
|
|
@@ -6899,7 +7034,7 @@ function previewFix(fix) {
|
|
|
6899
7034
|
}
|
|
6900
7035
|
}
|
|
6901
7036
|
async function createBackup(filePath, backupDir) {
|
|
6902
|
-
const backupPath =
|
|
7037
|
+
const backupPath = join16(backupDir, `${Date.now()}-${basename5(filePath)}`);
|
|
6903
7038
|
try {
|
|
6904
7039
|
await mkdir22(dirname7(backupPath), { recursive: true });
|
|
6905
7040
|
await copyFile2(filePath, backupPath);
|
|
@@ -6925,7 +7060,7 @@ async function applyDeleteFile(fix, config) {
|
|
|
6925
7060
|
}
|
|
6926
7061
|
async function applyDeleteLines(fix) {
|
|
6927
7062
|
if (fix.line !== void 0) {
|
|
6928
|
-
const content = await
|
|
7063
|
+
const content = await readFile62(fix.file, "utf-8");
|
|
6929
7064
|
const lines = content.split("\n");
|
|
6930
7065
|
lines.splice(fix.line - 1, 1);
|
|
6931
7066
|
await writeFile32(fix.file, lines.join("\n"));
|
|
@@ -6933,13 +7068,13 @@ async function applyDeleteLines(fix) {
|
|
|
6933
7068
|
}
|
|
6934
7069
|
async function applyReplace(fix) {
|
|
6935
7070
|
if (fix.oldContent && fix.newContent !== void 0) {
|
|
6936
|
-
const content = await
|
|
7071
|
+
const content = await readFile62(fix.file, "utf-8");
|
|
6937
7072
|
await writeFile32(fix.file, content.replace(fix.oldContent, fix.newContent));
|
|
6938
7073
|
}
|
|
6939
7074
|
}
|
|
6940
7075
|
async function applyInsert(fix) {
|
|
6941
7076
|
if (fix.line !== void 0 && fix.newContent) {
|
|
6942
|
-
const content = await
|
|
7077
|
+
const content = await readFile62(fix.file, "utf-8");
|
|
6943
7078
|
const lines = content.split("\n");
|
|
6944
7079
|
lines.splice(fix.line - 1, 0, fix.newContent);
|
|
6945
7080
|
await writeFile32(fix.file, lines.join("\n"));
|
|
@@ -7274,12 +7409,12 @@ function parseDiffHeader(part) {
|
|
|
7274
7409
|
return headerMatch[2];
|
|
7275
7410
|
}
|
|
7276
7411
|
function parseDiffPart(part) {
|
|
7277
|
-
const
|
|
7278
|
-
if (!
|
|
7412
|
+
const path42 = parseDiffHeader(part);
|
|
7413
|
+
if (!path42) return null;
|
|
7279
7414
|
const additionRegex = /^\+(?!\+\+)/gm;
|
|
7280
7415
|
const deletionRegex = /^-(?!--)/gm;
|
|
7281
7416
|
return {
|
|
7282
|
-
path:
|
|
7417
|
+
path: path42,
|
|
7283
7418
|
status: detectFileStatus(part),
|
|
7284
7419
|
additions: (part.match(additionRegex) || []).length,
|
|
7285
7420
|
deletions: (part.match(deletionRegex) || []).length
|
|
@@ -8064,10 +8199,10 @@ function detectEmergentConstraints(history, options) {
|
|
|
8064
8199
|
return { suggestions, totalViolationsAnalyzed, windowWeeks, minOccurrences };
|
|
8065
8200
|
}
|
|
8066
8201
|
function streamsDir(projectPath) {
|
|
8067
|
-
return
|
|
8202
|
+
return path7.join(projectPath, HARNESS_DIR, STREAMS_DIR);
|
|
8068
8203
|
}
|
|
8069
8204
|
function indexPath(projectPath) {
|
|
8070
|
-
return
|
|
8205
|
+
return path7.join(streamsDir(projectPath), INDEX_FILE);
|
|
8071
8206
|
}
|
|
8072
8207
|
function validateStreamName(name) {
|
|
8073
8208
|
if (!STREAM_NAME_REGEX.test(name)) {
|
|
@@ -8081,11 +8216,11 @@ function validateStreamName(name) {
|
|
|
8081
8216
|
}
|
|
8082
8217
|
async function loadStreamIndex(projectPath) {
|
|
8083
8218
|
const idxPath = indexPath(projectPath);
|
|
8084
|
-
if (!
|
|
8219
|
+
if (!fs10.existsSync(idxPath)) {
|
|
8085
8220
|
return Ok({ ...DEFAULT_STREAM_INDEX, streams: {} });
|
|
8086
8221
|
}
|
|
8087
8222
|
try {
|
|
8088
|
-
const raw =
|
|
8223
|
+
const raw = fs10.readFileSync(idxPath, "utf-8");
|
|
8089
8224
|
const parsed = JSON.parse(raw);
|
|
8090
8225
|
const result = StreamIndexSchema.safeParse(parsed);
|
|
8091
8226
|
if (!result.success) {
|
|
@@ -8103,8 +8238,8 @@ async function loadStreamIndex(projectPath) {
|
|
|
8103
8238
|
async function saveStreamIndex(projectPath, index) {
|
|
8104
8239
|
const dir = streamsDir(projectPath);
|
|
8105
8240
|
try {
|
|
8106
|
-
|
|
8107
|
-
|
|
8241
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
8242
|
+
fs10.writeFileSync(indexPath(projectPath), JSON.stringify(index, null, 2));
|
|
8108
8243
|
return Ok(void 0);
|
|
8109
8244
|
} catch (error) {
|
|
8110
8245
|
return Err(
|
|
@@ -8143,18 +8278,18 @@ async function resolveStreamPath(projectPath, options) {
|
|
|
8143
8278
|
)
|
|
8144
8279
|
);
|
|
8145
8280
|
}
|
|
8146
|
-
return Ok(
|
|
8281
|
+
return Ok(path7.join(streamsDir(projectPath), options.stream));
|
|
8147
8282
|
}
|
|
8148
8283
|
const branch = getCurrentBranch(projectPath);
|
|
8149
8284
|
if (branch && branch !== "main" && branch !== "master") {
|
|
8150
8285
|
for (const [name, info] of Object.entries(index.streams)) {
|
|
8151
8286
|
if (info.branch === branch) {
|
|
8152
|
-
return Ok(
|
|
8287
|
+
return Ok(path7.join(streamsDir(projectPath), name));
|
|
8153
8288
|
}
|
|
8154
8289
|
}
|
|
8155
8290
|
}
|
|
8156
8291
|
if (index.activeStream && index.streams[index.activeStream]) {
|
|
8157
|
-
return Ok(
|
|
8292
|
+
return Ok(path7.join(streamsDir(projectPath), index.activeStream));
|
|
8158
8293
|
}
|
|
8159
8294
|
return Err(
|
|
8160
8295
|
new Error(
|
|
@@ -8182,9 +8317,9 @@ async function createStream(projectPath, name, branch) {
|
|
|
8182
8317
|
if (index.streams[name]) {
|
|
8183
8318
|
return Err(new Error(`Stream '${name}' already exists`));
|
|
8184
8319
|
}
|
|
8185
|
-
const streamPath =
|
|
8320
|
+
const streamPath = path7.join(streamsDir(projectPath), name);
|
|
8186
8321
|
try {
|
|
8187
|
-
|
|
8322
|
+
fs10.mkdirSync(streamPath, { recursive: true });
|
|
8188
8323
|
} catch (error) {
|
|
8189
8324
|
return Err(
|
|
8190
8325
|
new Error(
|
|
@@ -8225,12 +8360,12 @@ async function archiveStream(projectPath, name) {
|
|
|
8225
8360
|
if (!index.streams[name]) {
|
|
8226
8361
|
return Err(new Error(`Stream '${name}' not found`));
|
|
8227
8362
|
}
|
|
8228
|
-
const streamPath =
|
|
8229
|
-
const archiveDir =
|
|
8363
|
+
const streamPath = path7.join(streamsDir(projectPath), name);
|
|
8364
|
+
const archiveDir = path7.join(projectPath, HARNESS_DIR, "archive", "streams");
|
|
8230
8365
|
try {
|
|
8231
|
-
|
|
8366
|
+
fs10.mkdirSync(archiveDir, { recursive: true });
|
|
8232
8367
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8233
|
-
|
|
8368
|
+
fs10.renameSync(streamPath, path7.join(archiveDir, `${name}-${date}`));
|
|
8234
8369
|
} catch (error) {
|
|
8235
8370
|
return Err(
|
|
8236
8371
|
new Error(
|
|
@@ -8251,19 +8386,19 @@ function getStreamForBranch(index, branch) {
|
|
|
8251
8386
|
return null;
|
|
8252
8387
|
}
|
|
8253
8388
|
async function migrateToStreams(projectPath) {
|
|
8254
|
-
const harnessDir =
|
|
8255
|
-
if (
|
|
8389
|
+
const harnessDir = path7.join(projectPath, HARNESS_DIR);
|
|
8390
|
+
if (fs10.existsSync(indexPath(projectPath))) {
|
|
8256
8391
|
return Ok(void 0);
|
|
8257
8392
|
}
|
|
8258
|
-
const filesToMove = STATE_FILES.filter((f) =>
|
|
8393
|
+
const filesToMove = STATE_FILES.filter((f) => fs10.existsSync(path7.join(harnessDir, f)));
|
|
8259
8394
|
if (filesToMove.length === 0) {
|
|
8260
8395
|
return Ok(void 0);
|
|
8261
8396
|
}
|
|
8262
|
-
const defaultDir =
|
|
8397
|
+
const defaultDir = path7.join(streamsDir(projectPath), "default");
|
|
8263
8398
|
try {
|
|
8264
|
-
|
|
8399
|
+
fs10.mkdirSync(defaultDir, { recursive: true });
|
|
8265
8400
|
for (const file of filesToMove) {
|
|
8266
|
-
|
|
8401
|
+
fs10.renameSync(path7.join(harnessDir, file), path7.join(defaultDir, file));
|
|
8267
8402
|
}
|
|
8268
8403
|
} catch (error) {
|
|
8269
8404
|
return Err(
|
|
@@ -8293,26 +8428,26 @@ function resolveSessionDir(projectPath, sessionSlug, options) {
|
|
|
8293
8428
|
new Error(`Invalid session slug '${sessionSlug}': must not contain path traversal characters`)
|
|
8294
8429
|
);
|
|
8295
8430
|
}
|
|
8296
|
-
const sessionDir =
|
|
8431
|
+
const sessionDir = path8.join(projectPath, HARNESS_DIR, SESSIONS_DIR, sessionSlug);
|
|
8297
8432
|
if (options?.create) {
|
|
8298
|
-
|
|
8433
|
+
fs11.mkdirSync(sessionDir, { recursive: true });
|
|
8299
8434
|
}
|
|
8300
8435
|
return Ok(sessionDir);
|
|
8301
8436
|
}
|
|
8302
8437
|
function updateSessionIndex(projectPath, sessionSlug, description) {
|
|
8303
|
-
const sessionsDir =
|
|
8304
|
-
|
|
8305
|
-
const indexPath2 =
|
|
8438
|
+
const sessionsDir = path8.join(projectPath, HARNESS_DIR, SESSIONS_DIR);
|
|
8439
|
+
fs11.mkdirSync(sessionsDir, { recursive: true });
|
|
8440
|
+
const indexPath2 = path8.join(sessionsDir, SESSION_INDEX_FILE);
|
|
8306
8441
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8307
8442
|
const newLine = `- [${sessionSlug}](${sessionSlug}/summary.md) \u2014 ${description} (${date})`;
|
|
8308
|
-
if (!
|
|
8309
|
-
|
|
8443
|
+
if (!fs11.existsSync(indexPath2)) {
|
|
8444
|
+
fs11.writeFileSync(indexPath2, `## Active Sessions
|
|
8310
8445
|
|
|
8311
8446
|
${newLine}
|
|
8312
8447
|
`);
|
|
8313
8448
|
return;
|
|
8314
8449
|
}
|
|
8315
|
-
const content =
|
|
8450
|
+
const content = fs11.readFileSync(indexPath2, "utf-8");
|
|
8316
8451
|
const lines = content.split("\n");
|
|
8317
8452
|
const slugPattern = `- [${sessionSlug}]`;
|
|
8318
8453
|
const existingIdx = lines.findIndex((l) => l.startsWith(slugPattern));
|
|
@@ -8322,7 +8457,7 @@ ${newLine}
|
|
|
8322
8457
|
const lastNonEmpty = lines.reduce((last, line, i) => line.trim() !== "" ? i : last, 0);
|
|
8323
8458
|
lines.splice(lastNonEmpty + 1, 0, newLine);
|
|
8324
8459
|
}
|
|
8325
|
-
|
|
8460
|
+
fs11.writeFileSync(indexPath2, lines.join("\n"));
|
|
8326
8461
|
}
|
|
8327
8462
|
function evictIfNeeded(map) {
|
|
8328
8463
|
if (map.size > MAX_CACHE_ENTRIES) {
|
|
@@ -8335,8 +8470,8 @@ async function getStateDir(projectPath, stream, session) {
|
|
|
8335
8470
|
const sessionResult = resolveSessionDir(projectPath, session, { create: true });
|
|
8336
8471
|
return sessionResult;
|
|
8337
8472
|
}
|
|
8338
|
-
const streamsIndexPath =
|
|
8339
|
-
const hasStreams =
|
|
8473
|
+
const streamsIndexPath = path9.join(projectPath, HARNESS_DIR, "streams", INDEX_FILE);
|
|
8474
|
+
const hasStreams = fs12.existsSync(streamsIndexPath);
|
|
8340
8475
|
if (stream || hasStreams) {
|
|
8341
8476
|
const result = await resolveStreamPath(projectPath, stream ? { stream } : void 0);
|
|
8342
8477
|
if (result.ok) {
|
|
@@ -8346,18 +8481,18 @@ async function getStateDir(projectPath, stream, session) {
|
|
|
8346
8481
|
return result;
|
|
8347
8482
|
}
|
|
8348
8483
|
}
|
|
8349
|
-
return Ok(
|
|
8484
|
+
return Ok(path9.join(projectPath, HARNESS_DIR));
|
|
8350
8485
|
}
|
|
8351
8486
|
async function loadState(projectPath, stream, session) {
|
|
8352
8487
|
try {
|
|
8353
8488
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8354
8489
|
if (!dirResult.ok) return dirResult;
|
|
8355
8490
|
const stateDir = dirResult.value;
|
|
8356
|
-
const statePath =
|
|
8357
|
-
if (!
|
|
8491
|
+
const statePath = path10.join(stateDir, STATE_FILE);
|
|
8492
|
+
if (!fs13.existsSync(statePath)) {
|
|
8358
8493
|
return Ok({ ...DEFAULT_STATE });
|
|
8359
8494
|
}
|
|
8360
|
-
const raw =
|
|
8495
|
+
const raw = fs13.readFileSync(statePath, "utf-8");
|
|
8361
8496
|
const parsed = JSON.parse(raw);
|
|
8362
8497
|
const result = HarnessStateSchema.safeParse(parsed);
|
|
8363
8498
|
if (!result.success) {
|
|
@@ -8375,11 +8510,11 @@ async function saveState(projectPath, state, stream, session) {
|
|
|
8375
8510
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8376
8511
|
if (!dirResult.ok) return dirResult;
|
|
8377
8512
|
const stateDir = dirResult.value;
|
|
8378
|
-
const statePath =
|
|
8379
|
-
|
|
8513
|
+
const statePath = path10.join(stateDir, STATE_FILE);
|
|
8514
|
+
fs13.mkdirSync(stateDir, { recursive: true });
|
|
8380
8515
|
const tmpPath = statePath + ".tmp";
|
|
8381
|
-
|
|
8382
|
-
|
|
8516
|
+
fs13.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
|
|
8517
|
+
fs13.renameSync(tmpPath, statePath);
|
|
8383
8518
|
return Ok(void 0);
|
|
8384
8519
|
} catch (error) {
|
|
8385
8520
|
return Err(
|
|
@@ -8465,10 +8600,10 @@ function computeContentHash(text) {
|
|
|
8465
8600
|
return crypto2.createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
8466
8601
|
}
|
|
8467
8602
|
function loadContentHashes(stateDir) {
|
|
8468
|
-
const hashesPath =
|
|
8469
|
-
if (!
|
|
8603
|
+
const hashesPath = path11.join(stateDir, CONTENT_HASHES_FILE);
|
|
8604
|
+
if (!fs14.existsSync(hashesPath)) return {};
|
|
8470
8605
|
try {
|
|
8471
|
-
const raw =
|
|
8606
|
+
const raw = fs14.readFileSync(hashesPath, "utf-8");
|
|
8472
8607
|
const parsed = JSON.parse(raw);
|
|
8473
8608
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
8474
8609
|
return parsed;
|
|
@@ -8477,15 +8612,15 @@ function loadContentHashes(stateDir) {
|
|
|
8477
8612
|
}
|
|
8478
8613
|
}
|
|
8479
8614
|
function saveContentHashes(stateDir, index) {
|
|
8480
|
-
const hashesPath =
|
|
8615
|
+
const hashesPath = path11.join(stateDir, CONTENT_HASHES_FILE);
|
|
8481
8616
|
const tmpPath = hashesPath + ".tmp";
|
|
8482
|
-
|
|
8483
|
-
|
|
8617
|
+
fs14.writeFileSync(tmpPath, JSON.stringify(index, null, 2) + "\n");
|
|
8618
|
+
fs14.renameSync(tmpPath, hashesPath);
|
|
8484
8619
|
}
|
|
8485
8620
|
function rebuildContentHashes(stateDir, learningsFile) {
|
|
8486
|
-
const learningsPath =
|
|
8487
|
-
if (!
|
|
8488
|
-
const content =
|
|
8621
|
+
const learningsPath = path11.join(stateDir, learningsFile);
|
|
8622
|
+
if (!fs14.existsSync(learningsPath)) return {};
|
|
8623
|
+
const content = fs14.readFileSync(learningsPath, "utf-8");
|
|
8489
8624
|
const lines = content.split("\n");
|
|
8490
8625
|
const index = {};
|
|
8491
8626
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8544,18 +8679,18 @@ async function loadRelevantLearnings(projectPath, skillName, stream, session) {
|
|
|
8544
8679
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8545
8680
|
if (!dirResult.ok) return dirResult;
|
|
8546
8681
|
const stateDir = dirResult.value;
|
|
8547
|
-
const learningsPath =
|
|
8548
|
-
if (!
|
|
8682
|
+
const learningsPath = path12.join(stateDir, LEARNINGS_FILE);
|
|
8683
|
+
if (!fs15.existsSync(learningsPath)) {
|
|
8549
8684
|
return Ok([]);
|
|
8550
8685
|
}
|
|
8551
|
-
const stats =
|
|
8686
|
+
const stats = fs15.statSync(learningsPath);
|
|
8552
8687
|
const cacheKey = learningsPath;
|
|
8553
8688
|
const cached = learningsCacheMap.get(cacheKey);
|
|
8554
8689
|
let entries;
|
|
8555
8690
|
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
8556
8691
|
entries = cached.entries;
|
|
8557
8692
|
} else {
|
|
8558
|
-
const content =
|
|
8693
|
+
const content = fs15.readFileSync(learningsPath, "utf-8");
|
|
8559
8694
|
const lines = content.split("\n");
|
|
8560
8695
|
entries = [];
|
|
8561
8696
|
let currentBlock = [];
|
|
@@ -8696,11 +8831,11 @@ function sleep(ms) {
|
|
|
8696
8831
|
async function acquireFileLock(lockPath) {
|
|
8697
8832
|
for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
|
|
8698
8833
|
try {
|
|
8699
|
-
const fd =
|
|
8834
|
+
const fd = fs16.openSync(
|
|
8700
8835
|
lockPath,
|
|
8701
|
-
|
|
8836
|
+
fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
|
|
8702
8837
|
);
|
|
8703
|
-
|
|
8838
|
+
fs16.closeSync(fd);
|
|
8704
8839
|
return;
|
|
8705
8840
|
} catch (err) {
|
|
8706
8841
|
const isExist = err instanceof Error && "code" in err && err.code === "EEXIST";
|
|
@@ -8714,20 +8849,20 @@ async function acquireFileLock(lockPath) {
|
|
|
8714
8849
|
}
|
|
8715
8850
|
function releaseFileLock(lockPath) {
|
|
8716
8851
|
try {
|
|
8717
|
-
|
|
8852
|
+
fs16.unlinkSync(lockPath);
|
|
8718
8853
|
} catch {
|
|
8719
8854
|
}
|
|
8720
8855
|
}
|
|
8721
8856
|
function loadOrRebuildHashes(stateDir, learningsPath) {
|
|
8722
|
-
const hashesPath =
|
|
8723
|
-
if (
|
|
8857
|
+
const hashesPath = path13.join(stateDir, CONTENT_HASHES_FILE);
|
|
8858
|
+
if (fs16.existsSync(hashesPath)) {
|
|
8724
8859
|
const hashes = loadContentHashes(stateDir);
|
|
8725
|
-
if (Object.keys(hashes).length === 0 &&
|
|
8860
|
+
if (Object.keys(hashes).length === 0 && fs16.existsSync(learningsPath)) {
|
|
8726
8861
|
return rebuildContentHashes(stateDir, LEARNINGS_FILE);
|
|
8727
8862
|
}
|
|
8728
8863
|
return hashes;
|
|
8729
8864
|
}
|
|
8730
|
-
if (
|
|
8865
|
+
if (fs16.existsSync(learningsPath)) {
|
|
8731
8866
|
return rebuildContentHashes(stateDir, LEARNINGS_FILE);
|
|
8732
8867
|
}
|
|
8733
8868
|
return {};
|
|
@@ -8751,8 +8886,8 @@ async function appendLearning(projectPath, learning, skillName, outcome, stream,
|
|
|
8751
8886
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8752
8887
|
if (!dirResult.ok) return dirResult;
|
|
8753
8888
|
const stateDir = dirResult.value;
|
|
8754
|
-
const learningsPath =
|
|
8755
|
-
|
|
8889
|
+
const learningsPath = path13.join(stateDir, LEARNINGS_FILE);
|
|
8890
|
+
fs16.mkdirSync(stateDir, { recursive: true });
|
|
8756
8891
|
const lockPath = learningsPath + ".lock";
|
|
8757
8892
|
await acquireFileLock(lockPath);
|
|
8758
8893
|
try {
|
|
@@ -8782,17 +8917,17 @@ ${bulletLine}
|
|
|
8782
8917
|
`;
|
|
8783
8918
|
let overlapResult;
|
|
8784
8919
|
let existingLineCount;
|
|
8785
|
-
if (!
|
|
8786
|
-
|
|
8920
|
+
if (!fs16.existsSync(learningsPath)) {
|
|
8921
|
+
fs16.writeFileSync(learningsPath, `# Learnings
|
|
8787
8922
|
${entry}`);
|
|
8788
8923
|
existingLineCount = 1;
|
|
8789
8924
|
} else {
|
|
8790
|
-
const existingContent =
|
|
8925
|
+
const existingContent = fs16.readFileSync(learningsPath, "utf-8");
|
|
8791
8926
|
const existingEntries = existingContent.split("\n").filter((line) => /^- \*\*\d{4}-\d{2}-\d{2}/.test(line));
|
|
8792
8927
|
const overlap = checkOverlap(bulletLine, existingEntries);
|
|
8793
8928
|
if (overlap.score >= 0.7) overlapResult = overlap;
|
|
8794
8929
|
existingLineCount = existingContent.split("\n").length;
|
|
8795
|
-
|
|
8930
|
+
fs16.appendFileSync(learningsPath, entry);
|
|
8796
8931
|
}
|
|
8797
8932
|
const bulletLineNum = existingLineCount + 2;
|
|
8798
8933
|
contentHashes[contentHash] = { date: timestamp ?? "", line: bulletLineNum };
|
|
@@ -8897,11 +9032,11 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
|
|
|
8897
9032
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
8898
9033
|
if (!dirResult.ok) return dirResult;
|
|
8899
9034
|
const stateDir = dirResult.value;
|
|
8900
|
-
const learningsPath =
|
|
8901
|
-
if (!
|
|
9035
|
+
const learningsPath = path13.join(stateDir, LEARNINGS_FILE);
|
|
9036
|
+
if (!fs16.existsSync(learningsPath)) {
|
|
8902
9037
|
return Ok([]);
|
|
8903
9038
|
}
|
|
8904
|
-
const content =
|
|
9039
|
+
const content = fs16.readFileSync(learningsPath, "utf-8");
|
|
8905
9040
|
const lines = content.split("\n");
|
|
8906
9041
|
const indexEntries = [];
|
|
8907
9042
|
let pendingFrontmatter = null;
|
|
@@ -8943,16 +9078,16 @@ async function archiveLearnings(projectPath, entries, stream) {
|
|
|
8943
9078
|
const dirResult = await getStateDir(projectPath, stream);
|
|
8944
9079
|
if (!dirResult.ok) return dirResult;
|
|
8945
9080
|
const stateDir = dirResult.value;
|
|
8946
|
-
const archiveDir =
|
|
8947
|
-
|
|
9081
|
+
const archiveDir = path14.join(stateDir, "learnings-archive");
|
|
9082
|
+
fs17.mkdirSync(archiveDir, { recursive: true });
|
|
8948
9083
|
const now = /* @__PURE__ */ new Date();
|
|
8949
9084
|
const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
|
|
8950
|
-
const archivePath =
|
|
9085
|
+
const archivePath = path14.join(archiveDir, `${yearMonth}.md`);
|
|
8951
9086
|
const archiveContent = entries.join("\n\n") + "\n";
|
|
8952
|
-
if (
|
|
8953
|
-
|
|
9087
|
+
if (fs17.existsSync(archivePath)) {
|
|
9088
|
+
fs17.appendFileSync(archivePath, "\n" + archiveContent);
|
|
8954
9089
|
} else {
|
|
8955
|
-
|
|
9090
|
+
fs17.writeFileSync(archivePath, `# Learnings Archive
|
|
8956
9091
|
|
|
8957
9092
|
${archiveContent}`);
|
|
8958
9093
|
}
|
|
@@ -8970,8 +9105,8 @@ async function pruneLearnings(projectPath, stream) {
|
|
|
8970
9105
|
const dirResult = await getStateDir(projectPath, stream);
|
|
8971
9106
|
if (!dirResult.ok) return dirResult;
|
|
8972
9107
|
const stateDir = dirResult.value;
|
|
8973
|
-
const learningsPath =
|
|
8974
|
-
if (!
|
|
9108
|
+
const learningsPath = path14.join(stateDir, LEARNINGS_FILE);
|
|
9109
|
+
if (!fs17.existsSync(learningsPath)) {
|
|
8975
9110
|
return Ok({ kept: 0, archived: 0, patterns: [] });
|
|
8976
9111
|
}
|
|
8977
9112
|
const loadResult = await loadRelevantLearnings(projectPath, void 0, stream);
|
|
@@ -9002,7 +9137,7 @@ async function pruneLearnings(projectPath, stream) {
|
|
|
9002
9137
|
if (!archiveResult.ok) return archiveResult;
|
|
9003
9138
|
}
|
|
9004
9139
|
const newContent = "# Learnings\n\n" + toKeep.join("\n\n") + "\n";
|
|
9005
|
-
|
|
9140
|
+
fs17.writeFileSync(learningsPath, newContent);
|
|
9006
9141
|
invalidateLearningsCacheEntry(learningsPath);
|
|
9007
9142
|
return Ok({
|
|
9008
9143
|
kept: toKeep.length,
|
|
@@ -9046,19 +9181,19 @@ async function promoteSessionLearnings(projectPath, sessionSlug, stream) {
|
|
|
9046
9181
|
const dirResult = await getStateDir(projectPath, stream);
|
|
9047
9182
|
if (!dirResult.ok) return dirResult;
|
|
9048
9183
|
const stateDir = dirResult.value;
|
|
9049
|
-
const globalPath =
|
|
9050
|
-
const existingGlobal =
|
|
9184
|
+
const globalPath = path14.join(stateDir, LEARNINGS_FILE);
|
|
9185
|
+
const existingGlobal = fs17.existsSync(globalPath) ? fs17.readFileSync(globalPath, "utf-8") : "";
|
|
9051
9186
|
const newEntries = toPromote.filter((entry) => !existingGlobal.includes(entry.trim()));
|
|
9052
9187
|
if (newEntries.length === 0) {
|
|
9053
9188
|
return Ok({ promoted: 0, skipped: skipped + toPromote.length });
|
|
9054
9189
|
}
|
|
9055
9190
|
const promotedContent = newEntries.join("\n\n") + "\n";
|
|
9056
9191
|
if (!existingGlobal) {
|
|
9057
|
-
|
|
9192
|
+
fs17.writeFileSync(globalPath, `# Learnings
|
|
9058
9193
|
|
|
9059
9194
|
${promotedContent}`);
|
|
9060
9195
|
} else {
|
|
9061
|
-
|
|
9196
|
+
fs17.appendFileSync(globalPath, "\n\n" + promotedContent);
|
|
9062
9197
|
}
|
|
9063
9198
|
invalidateLearningsCacheEntry(globalPath);
|
|
9064
9199
|
return Ok({
|
|
@@ -9094,13 +9229,13 @@ async function detectStaleLearnings(projectPath, stream, session) {
|
|
|
9094
9229
|
freshCount++;
|
|
9095
9230
|
continue;
|
|
9096
9231
|
}
|
|
9097
|
-
const resolvedRoot =
|
|
9232
|
+
const resolvedRoot = path15.resolve(projectPath);
|
|
9098
9233
|
const missing = refs.filter((ref) => {
|
|
9099
|
-
const absPath =
|
|
9100
|
-
if (!absPath.startsWith(resolvedRoot +
|
|
9234
|
+
const absPath = path15.resolve(projectPath, ref);
|
|
9235
|
+
if (!absPath.startsWith(resolvedRoot + path15.sep) && absPath !== resolvedRoot) {
|
|
9101
9236
|
return false;
|
|
9102
9237
|
}
|
|
9103
|
-
return !
|
|
9238
|
+
return !fs18.existsSync(absPath);
|
|
9104
9239
|
});
|
|
9105
9240
|
if (missing.length > 0) {
|
|
9106
9241
|
const idx = extractIndexEntry(entry);
|
|
@@ -9135,17 +9270,17 @@ async function appendFailure(projectPath, description, skillName, type, stream,
|
|
|
9135
9270
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
9136
9271
|
if (!dirResult.ok) return dirResult;
|
|
9137
9272
|
const stateDir = dirResult.value;
|
|
9138
|
-
const failuresPath =
|
|
9139
|
-
|
|
9273
|
+
const failuresPath = path16.join(stateDir, FAILURES_FILE);
|
|
9274
|
+
fs19.mkdirSync(stateDir, { recursive: true });
|
|
9140
9275
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
9141
9276
|
const entry = `
|
|
9142
9277
|
- **${timestamp} [skill:${skillName}] [type:${type}]:** ${description}
|
|
9143
9278
|
`;
|
|
9144
|
-
if (!
|
|
9145
|
-
|
|
9279
|
+
if (!fs19.existsSync(failuresPath)) {
|
|
9280
|
+
fs19.writeFileSync(failuresPath, `# Failures
|
|
9146
9281
|
${entry}`);
|
|
9147
9282
|
} else {
|
|
9148
|
-
|
|
9283
|
+
fs19.appendFileSync(failuresPath, entry);
|
|
9149
9284
|
}
|
|
9150
9285
|
failuresCacheMap.delete(failuresPath);
|
|
9151
9286
|
return Ok(void 0);
|
|
@@ -9162,17 +9297,17 @@ async function loadFailures(projectPath, stream, session) {
|
|
|
9162
9297
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
9163
9298
|
if (!dirResult.ok) return dirResult;
|
|
9164
9299
|
const stateDir = dirResult.value;
|
|
9165
|
-
const failuresPath =
|
|
9166
|
-
if (!
|
|
9300
|
+
const failuresPath = path16.join(stateDir, FAILURES_FILE);
|
|
9301
|
+
if (!fs19.existsSync(failuresPath)) {
|
|
9167
9302
|
return Ok([]);
|
|
9168
9303
|
}
|
|
9169
|
-
const stats =
|
|
9304
|
+
const stats = fs19.statSync(failuresPath);
|
|
9170
9305
|
const cacheKey = failuresPath;
|
|
9171
9306
|
const cached = failuresCacheMap.get(cacheKey);
|
|
9172
9307
|
if (cached && cached.mtimeMs === stats.mtimeMs) {
|
|
9173
9308
|
return Ok(cached.entries);
|
|
9174
9309
|
}
|
|
9175
|
-
const content =
|
|
9310
|
+
const content = fs19.readFileSync(failuresPath, "utf-8");
|
|
9176
9311
|
const entries = [];
|
|
9177
9312
|
for (const line of content.split("\n")) {
|
|
9178
9313
|
const match = line.match(FAILURE_LINE_REGEX);
|
|
@@ -9201,20 +9336,20 @@ async function archiveFailures(projectPath, stream, session) {
|
|
|
9201
9336
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
9202
9337
|
if (!dirResult.ok) return dirResult;
|
|
9203
9338
|
const stateDir = dirResult.value;
|
|
9204
|
-
const failuresPath =
|
|
9205
|
-
if (!
|
|
9339
|
+
const failuresPath = path16.join(stateDir, FAILURES_FILE);
|
|
9340
|
+
if (!fs19.existsSync(failuresPath)) {
|
|
9206
9341
|
return Ok(void 0);
|
|
9207
9342
|
}
|
|
9208
|
-
const archiveDir =
|
|
9209
|
-
|
|
9343
|
+
const archiveDir = path16.join(stateDir, "archive");
|
|
9344
|
+
fs19.mkdirSync(archiveDir, { recursive: true });
|
|
9210
9345
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
9211
9346
|
let archiveName = `failures-${date}.md`;
|
|
9212
9347
|
let counter = 2;
|
|
9213
|
-
while (
|
|
9348
|
+
while (fs19.existsSync(path16.join(archiveDir, archiveName))) {
|
|
9214
9349
|
archiveName = `failures-${date}-${counter}.md`;
|
|
9215
9350
|
counter++;
|
|
9216
9351
|
}
|
|
9217
|
-
|
|
9352
|
+
fs19.renameSync(failuresPath, path16.join(archiveDir, archiveName));
|
|
9218
9353
|
failuresCacheMap.delete(failuresPath);
|
|
9219
9354
|
return Ok(void 0);
|
|
9220
9355
|
} catch (error) {
|
|
@@ -9230,11 +9365,11 @@ async function saveHandoff(projectPath, handoff, stream, session) {
|
|
|
9230
9365
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
9231
9366
|
if (!dirResult.ok) return dirResult;
|
|
9232
9367
|
const stateDir = dirResult.value;
|
|
9233
|
-
const handoffPath =
|
|
9234
|
-
|
|
9368
|
+
const handoffPath = path17.join(stateDir, HANDOFF_FILE);
|
|
9369
|
+
fs20.mkdirSync(stateDir, { recursive: true });
|
|
9235
9370
|
const tmpPath = handoffPath + ".tmp";
|
|
9236
|
-
|
|
9237
|
-
|
|
9371
|
+
fs20.writeFileSync(tmpPath, JSON.stringify(handoff, null, 2));
|
|
9372
|
+
fs20.renameSync(tmpPath, handoffPath);
|
|
9238
9373
|
return Ok(void 0);
|
|
9239
9374
|
} catch (error) {
|
|
9240
9375
|
return Err(
|
|
@@ -9247,11 +9382,11 @@ async function loadHandoff(projectPath, stream, session) {
|
|
|
9247
9382
|
const dirResult = await getStateDir(projectPath, stream, session);
|
|
9248
9383
|
if (!dirResult.ok) return dirResult;
|
|
9249
9384
|
const stateDir = dirResult.value;
|
|
9250
|
-
const handoffPath =
|
|
9251
|
-
if (!
|
|
9385
|
+
const handoffPath = path17.join(stateDir, HANDOFF_FILE);
|
|
9386
|
+
if (!fs20.existsSync(handoffPath)) {
|
|
9252
9387
|
return Ok(null);
|
|
9253
9388
|
}
|
|
9254
|
-
const raw =
|
|
9389
|
+
const raw = fs20.readFileSync(handoffPath, "utf-8");
|
|
9255
9390
|
const parsed = JSON.parse(raw);
|
|
9256
9391
|
const result = HandoffSchema.safeParse(parsed);
|
|
9257
9392
|
if (!result.success) {
|
|
@@ -9265,28 +9400,28 @@ async function loadHandoff(projectPath, stream, session) {
|
|
|
9265
9400
|
}
|
|
9266
9401
|
}
|
|
9267
9402
|
function loadChecksFromConfig(gateConfigPath) {
|
|
9268
|
-
if (!
|
|
9269
|
-
const raw = JSON.parse(
|
|
9403
|
+
if (!fs21.existsSync(gateConfigPath)) return [];
|
|
9404
|
+
const raw = JSON.parse(fs21.readFileSync(gateConfigPath, "utf-8"));
|
|
9270
9405
|
const config = GateConfigSchema.safeParse(raw);
|
|
9271
9406
|
if (config.success && config.data.checks) return config.data.checks;
|
|
9272
9407
|
return [];
|
|
9273
9408
|
}
|
|
9274
9409
|
function discoverChecksFromProject(projectPath) {
|
|
9275
9410
|
const checks = [];
|
|
9276
|
-
const packageJsonPath =
|
|
9277
|
-
if (
|
|
9278
|
-
const pkg = JSON.parse(
|
|
9411
|
+
const packageJsonPath = path18.join(projectPath, "package.json");
|
|
9412
|
+
if (fs21.existsSync(packageJsonPath)) {
|
|
9413
|
+
const pkg = JSON.parse(fs21.readFileSync(packageJsonPath, "utf-8"));
|
|
9279
9414
|
const scripts = pkg.scripts || {};
|
|
9280
9415
|
if (scripts.test) checks.push({ name: "test", command: "npm test" });
|
|
9281
9416
|
if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
|
|
9282
9417
|
if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
|
|
9283
9418
|
if (scripts.build) checks.push({ name: "build", command: "npm run build" });
|
|
9284
9419
|
}
|
|
9285
|
-
if (
|
|
9420
|
+
if (fs21.existsSync(path18.join(projectPath, "go.mod"))) {
|
|
9286
9421
|
checks.push({ name: "test", command: "go test ./..." });
|
|
9287
9422
|
checks.push({ name: "build", command: "go build ./..." });
|
|
9288
9423
|
}
|
|
9289
|
-
if (
|
|
9424
|
+
if (fs21.existsSync(path18.join(projectPath, "pyproject.toml")) || fs21.existsSync(path18.join(projectPath, "setup.py"))) {
|
|
9290
9425
|
checks.push({ name: "test", command: "python -m pytest" });
|
|
9291
9426
|
}
|
|
9292
9427
|
return checks;
|
|
@@ -9326,8 +9461,8 @@ function executeCheck(check, projectPath) {
|
|
|
9326
9461
|
}
|
|
9327
9462
|
}
|
|
9328
9463
|
async function runMechanicalGate(projectPath) {
|
|
9329
|
-
const harnessDir =
|
|
9330
|
-
const gateConfigPath =
|
|
9464
|
+
const harnessDir = path18.join(projectPath, HARNESS_DIR);
|
|
9465
|
+
const gateConfigPath = path18.join(harnessDir, GATE_CONFIG_FILE);
|
|
9331
9466
|
try {
|
|
9332
9467
|
let checks = loadChecksFromConfig(gateConfigPath);
|
|
9333
9468
|
if (checks.length === 0) {
|
|
@@ -9383,9 +9518,9 @@ function writeSessionSummary(projectPath, sessionSlug, data) {
|
|
|
9383
9518
|
const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
|
|
9384
9519
|
if (!dirResult.ok) return dirResult;
|
|
9385
9520
|
const sessionDir = dirResult.value;
|
|
9386
|
-
const summaryPath =
|
|
9521
|
+
const summaryPath = path19.join(sessionDir, SUMMARY_FILE);
|
|
9387
9522
|
const content = formatSummary(data);
|
|
9388
|
-
|
|
9523
|
+
fs22.writeFileSync(summaryPath, content);
|
|
9389
9524
|
const description = deriveIndexDescription(data);
|
|
9390
9525
|
updateSessionIndex(projectPath, sessionSlug, description);
|
|
9391
9526
|
return Ok(void 0);
|
|
@@ -9402,11 +9537,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
|
|
|
9402
9537
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
9403
9538
|
if (!dirResult.ok) return dirResult;
|
|
9404
9539
|
const sessionDir = dirResult.value;
|
|
9405
|
-
const summaryPath =
|
|
9406
|
-
if (!
|
|
9540
|
+
const summaryPath = path19.join(sessionDir, SUMMARY_FILE);
|
|
9541
|
+
if (!fs22.existsSync(summaryPath)) {
|
|
9407
9542
|
return Ok(null);
|
|
9408
9543
|
}
|
|
9409
|
-
const content =
|
|
9544
|
+
const content = fs22.readFileSync(summaryPath, "utf-8");
|
|
9410
9545
|
return Ok(content);
|
|
9411
9546
|
} catch (error) {
|
|
9412
9547
|
return Err(
|
|
@@ -9418,11 +9553,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
|
|
|
9418
9553
|
}
|
|
9419
9554
|
function listActiveSessions(projectPath) {
|
|
9420
9555
|
try {
|
|
9421
|
-
const indexPath2 =
|
|
9422
|
-
if (!
|
|
9556
|
+
const indexPath2 = path19.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
|
|
9557
|
+
if (!fs22.existsSync(indexPath2)) {
|
|
9423
9558
|
return Ok(null);
|
|
9424
9559
|
}
|
|
9425
|
-
const content =
|
|
9560
|
+
const content = fs22.readFileSync(indexPath2, "utf-8");
|
|
9426
9561
|
return Ok(content);
|
|
9427
9562
|
} catch (error) {
|
|
9428
9563
|
return Err(
|
|
@@ -9443,12 +9578,12 @@ async function loadSessionState(projectPath, sessionSlug) {
|
|
|
9443
9578
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
9444
9579
|
if (!dirResult.ok) return dirResult;
|
|
9445
9580
|
const sessionDir = dirResult.value;
|
|
9446
|
-
const filePath =
|
|
9447
|
-
if (!
|
|
9581
|
+
const filePath = path20.join(sessionDir, SESSION_STATE_FILE);
|
|
9582
|
+
if (!fs23.existsSync(filePath)) {
|
|
9448
9583
|
return Ok(emptySections());
|
|
9449
9584
|
}
|
|
9450
9585
|
try {
|
|
9451
|
-
const raw =
|
|
9586
|
+
const raw = fs23.readFileSync(filePath, "utf-8");
|
|
9452
9587
|
const parsed = JSON.parse(raw);
|
|
9453
9588
|
const sections = emptySections();
|
|
9454
9589
|
for (const name of SESSION_SECTION_NAMES) {
|
|
@@ -9469,9 +9604,9 @@ async function saveSessionState(projectPath, sessionSlug, sections) {
|
|
|
9469
9604
|
const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
|
|
9470
9605
|
if (!dirResult.ok) return dirResult;
|
|
9471
9606
|
const sessionDir = dirResult.value;
|
|
9472
|
-
const filePath =
|
|
9607
|
+
const filePath = path20.join(sessionDir, SESSION_STATE_FILE);
|
|
9473
9608
|
try {
|
|
9474
|
-
|
|
9609
|
+
fs23.writeFileSync(filePath, JSON.stringify(sections, null, 2));
|
|
9475
9610
|
return Ok(void 0);
|
|
9476
9611
|
} catch (error) {
|
|
9477
9612
|
return Err(
|
|
@@ -9527,26 +9662,26 @@ async function archiveSession(projectPath, sessionSlug) {
|
|
|
9527
9662
|
const dirResult = resolveSessionDir(projectPath, sessionSlug);
|
|
9528
9663
|
if (!dirResult.ok) return dirResult;
|
|
9529
9664
|
const sessionDir = dirResult.value;
|
|
9530
|
-
if (!
|
|
9665
|
+
if (!fs24.existsSync(sessionDir)) {
|
|
9531
9666
|
return Err(new Error(`Session '${sessionSlug}' not found at ${sessionDir}`));
|
|
9532
9667
|
}
|
|
9533
|
-
const archiveBase =
|
|
9668
|
+
const archiveBase = path21.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
|
|
9534
9669
|
try {
|
|
9535
|
-
|
|
9670
|
+
fs24.mkdirSync(archiveBase, { recursive: true });
|
|
9536
9671
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
9537
9672
|
let archiveName = `${sessionSlug}-${date}`;
|
|
9538
9673
|
let counter = 1;
|
|
9539
|
-
while (
|
|
9674
|
+
while (fs24.existsSync(path21.join(archiveBase, archiveName))) {
|
|
9540
9675
|
archiveName = `${sessionSlug}-${date}-${counter}`;
|
|
9541
9676
|
counter++;
|
|
9542
9677
|
}
|
|
9543
|
-
const dest =
|
|
9678
|
+
const dest = path21.join(archiveBase, archiveName);
|
|
9544
9679
|
try {
|
|
9545
|
-
|
|
9680
|
+
fs24.renameSync(sessionDir, dest);
|
|
9546
9681
|
} catch (renameErr) {
|
|
9547
9682
|
if (renameErr instanceof Error && "code" in renameErr && renameErr.code === "EXDEV") {
|
|
9548
|
-
|
|
9549
|
-
|
|
9683
|
+
fs24.cpSync(sessionDir, dest, { recursive: true });
|
|
9684
|
+
fs24.rmSync(sessionDir, { recursive: true });
|
|
9550
9685
|
} else {
|
|
9551
9686
|
throw renameErr;
|
|
9552
9687
|
}
|
|
@@ -9568,8 +9703,8 @@ function loadKnownHashes(eventsPath) {
|
|
|
9568
9703
|
const cached = knownHashesCache.get(eventsPath);
|
|
9569
9704
|
if (cached) return cached;
|
|
9570
9705
|
const hashes = /* @__PURE__ */ new Set();
|
|
9571
|
-
if (
|
|
9572
|
-
const content =
|
|
9706
|
+
if (fs25.existsSync(eventsPath)) {
|
|
9707
|
+
const content = fs25.readFileSync(eventsPath, "utf-8");
|
|
9573
9708
|
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
9574
9709
|
for (const line of lines) {
|
|
9575
9710
|
try {
|
|
@@ -9592,8 +9727,8 @@ async function emitEvent(projectPath, event, options) {
|
|
|
9592
9727
|
const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
|
|
9593
9728
|
if (!dirResult.ok) return dirResult;
|
|
9594
9729
|
const stateDir = dirResult.value;
|
|
9595
|
-
const eventsPath =
|
|
9596
|
-
|
|
9730
|
+
const eventsPath = path22.join(stateDir, EVENTS_FILE);
|
|
9731
|
+
fs25.mkdirSync(stateDir, { recursive: true });
|
|
9597
9732
|
const contentHash = computeEventHash(event, options?.session);
|
|
9598
9733
|
const knownHashes = loadKnownHashes(eventsPath);
|
|
9599
9734
|
if (knownHashes.has(contentHash)) {
|
|
@@ -9607,7 +9742,7 @@ async function emitEvent(projectPath, event, options) {
|
|
|
9607
9742
|
if (options?.session) {
|
|
9608
9743
|
fullEvent.session = options.session;
|
|
9609
9744
|
}
|
|
9610
|
-
|
|
9745
|
+
fs25.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
|
|
9611
9746
|
knownHashes.add(contentHash);
|
|
9612
9747
|
return Ok({ written: true });
|
|
9613
9748
|
} catch (error) {
|
|
@@ -9621,11 +9756,11 @@ async function loadEvents(projectPath, options) {
|
|
|
9621
9756
|
const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
|
|
9622
9757
|
if (!dirResult.ok) return dirResult;
|
|
9623
9758
|
const stateDir = dirResult.value;
|
|
9624
|
-
const eventsPath =
|
|
9625
|
-
if (!
|
|
9759
|
+
const eventsPath = path22.join(stateDir, EVENTS_FILE);
|
|
9760
|
+
if (!fs25.existsSync(eventsPath)) {
|
|
9626
9761
|
return Ok([]);
|
|
9627
9762
|
}
|
|
9628
|
-
const content =
|
|
9763
|
+
const content = fs25.readFileSync(eventsPath, "utf-8");
|
|
9629
9764
|
const lines = content.split("\n").filter((line) => line.trim() !== "");
|
|
9630
9765
|
const events = [];
|
|
9631
9766
|
for (const line of lines) {
|
|
@@ -9874,11 +10009,11 @@ function nodeSubStacks(allDeps) {
|
|
|
9874
10009
|
return found;
|
|
9875
10010
|
}
|
|
9876
10011
|
function detectNodeStacks(projectRoot) {
|
|
9877
|
-
const pkgJsonPath =
|
|
9878
|
-
if (!
|
|
10012
|
+
const pkgJsonPath = path23.join(projectRoot, "package.json");
|
|
10013
|
+
if (!fs26.existsSync(pkgJsonPath)) return [];
|
|
9879
10014
|
const stacks = ["node"];
|
|
9880
10015
|
try {
|
|
9881
|
-
const pkgJson = JSON.parse(
|
|
10016
|
+
const pkgJson = JSON.parse(fs26.readFileSync(pkgJsonPath, "utf-8"));
|
|
9882
10017
|
const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
|
|
9883
10018
|
stacks.push(...nodeSubStacks(allDeps));
|
|
9884
10019
|
} catch {
|
|
@@ -9887,10 +10022,10 @@ function detectNodeStacks(projectRoot) {
|
|
|
9887
10022
|
}
|
|
9888
10023
|
function detectStack(projectRoot) {
|
|
9889
10024
|
const stacks = [...detectNodeStacks(projectRoot)];
|
|
9890
|
-
if (
|
|
10025
|
+
if (fs26.existsSync(path23.join(projectRoot, "go.mod"))) {
|
|
9891
10026
|
stacks.push("go");
|
|
9892
10027
|
}
|
|
9893
|
-
const hasPython =
|
|
10028
|
+
const hasPython = fs26.existsSync(path23.join(projectRoot, "requirements.txt")) || fs26.existsSync(path23.join(projectRoot, "pyproject.toml"));
|
|
9894
10029
|
if (hasPython) {
|
|
9895
10030
|
stacks.push("python");
|
|
9896
10031
|
}
|
|
@@ -9933,7 +10068,7 @@ function getInjectionPatterns() {
|
|
|
9933
10068
|
}
|
|
9934
10069
|
function getTaintFilePath(projectRoot, sessionId) {
|
|
9935
10070
|
const id = sessionId || DEFAULT_SESSION_ID;
|
|
9936
|
-
return
|
|
10071
|
+
return join382(projectRoot, ".harness", `session-taint-${id}.json`);
|
|
9937
10072
|
}
|
|
9938
10073
|
function readTaint(projectRoot, sessionId) {
|
|
9939
10074
|
const filePath = getTaintFilePath(projectRoot, sessionId);
|
|
@@ -10015,14 +10150,14 @@ function clearTaint(projectRoot, sessionId) {
|
|
|
10015
10150
|
return 0;
|
|
10016
10151
|
}
|
|
10017
10152
|
}
|
|
10018
|
-
const harnessDir =
|
|
10153
|
+
const harnessDir = join382(projectRoot, ".harness");
|
|
10019
10154
|
let count = 0;
|
|
10020
10155
|
try {
|
|
10021
10156
|
const files = readdirSync3(harnessDir);
|
|
10022
10157
|
for (const file of files) {
|
|
10023
10158
|
if (file.startsWith("session-taint-") && file.endsWith(".json")) {
|
|
10024
10159
|
try {
|
|
10025
|
-
unlinkSync2(
|
|
10160
|
+
unlinkSync2(join382(harnessDir, file));
|
|
10026
10161
|
count++;
|
|
10027
10162
|
} catch {
|
|
10028
10163
|
}
|
|
@@ -10033,7 +10168,7 @@ function clearTaint(projectRoot, sessionId) {
|
|
|
10033
10168
|
return count;
|
|
10034
10169
|
}
|
|
10035
10170
|
function listTaintedSessions(projectRoot) {
|
|
10036
|
-
const harnessDir =
|
|
10171
|
+
const harnessDir = join382(projectRoot, ".harness");
|
|
10037
10172
|
const sessions = [];
|
|
10038
10173
|
try {
|
|
10039
10174
|
const files = readdirSync3(harnessDir);
|
|
@@ -10105,7 +10240,7 @@ function securityFindingId(finding) {
|
|
|
10105
10240
|
}
|
|
10106
10241
|
async function runValidateCheck(projectRoot, config) {
|
|
10107
10242
|
const issues = [];
|
|
10108
|
-
const agentsPath =
|
|
10243
|
+
const agentsPath = path24.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
|
|
10109
10244
|
const result = await validateAgentsMap(agentsPath);
|
|
10110
10245
|
if (!result.ok) {
|
|
10111
10246
|
issues.push({ severity: "error", message: result.error.message });
|
|
@@ -10162,7 +10297,7 @@ async function runDepsCheck(projectRoot, config) {
|
|
|
10162
10297
|
}
|
|
10163
10298
|
async function runDocsCheck(projectRoot, config) {
|
|
10164
10299
|
const issues = [];
|
|
10165
|
-
const docsDir =
|
|
10300
|
+
const docsDir = path24.join(projectRoot, config.docsDir ?? "docs");
|
|
10166
10301
|
const entropyConfig = config.entropy || {};
|
|
10167
10302
|
const result = await checkDocCoverage("project", {
|
|
10168
10303
|
docsDir,
|
|
@@ -10347,7 +10482,7 @@ async function runTraceabilityCheck(projectRoot, config) {
|
|
|
10347
10482
|
const issues = [];
|
|
10348
10483
|
const traceConfig = config.traceability || {};
|
|
10349
10484
|
if (traceConfig.enabled === false) return issues;
|
|
10350
|
-
const graphDir =
|
|
10485
|
+
const graphDir = path24.join(projectRoot, ".harness", "graph");
|
|
10351
10486
|
const store = new GraphStore();
|
|
10352
10487
|
const loaded = await store.load(graphDir);
|
|
10353
10488
|
if (!loaded) {
|
|
@@ -10525,7 +10660,7 @@ async function runMechanicalChecks(options) {
|
|
|
10525
10660
|
};
|
|
10526
10661
|
if (!skip.includes("validate")) {
|
|
10527
10662
|
try {
|
|
10528
|
-
const agentsPath =
|
|
10663
|
+
const agentsPath = path25.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
|
|
10529
10664
|
const result = await validateAgentsMap(agentsPath);
|
|
10530
10665
|
if (!result.ok) {
|
|
10531
10666
|
statuses.validate = "fail";
|
|
@@ -10562,7 +10697,7 @@ async function runMechanicalChecks(options) {
|
|
|
10562
10697
|
statuses.validate = "fail";
|
|
10563
10698
|
findings.push({
|
|
10564
10699
|
tool: "validate",
|
|
10565
|
-
file:
|
|
10700
|
+
file: path25.join(projectRoot, "AGENTS.md"),
|
|
10566
10701
|
message: err instanceof Error ? err.message : String(err),
|
|
10567
10702
|
severity: "error"
|
|
10568
10703
|
});
|
|
@@ -10626,7 +10761,7 @@ async function runMechanicalChecks(options) {
|
|
|
10626
10761
|
(async () => {
|
|
10627
10762
|
const localFindings = [];
|
|
10628
10763
|
try {
|
|
10629
|
-
const docsDir =
|
|
10764
|
+
const docsDir = path25.join(projectRoot, config.docsDir ?? "docs");
|
|
10630
10765
|
const result = await checkDocCoverage("project", { docsDir });
|
|
10631
10766
|
if (!result.ok) {
|
|
10632
10767
|
statuses["check-docs"] = "warn";
|
|
@@ -10653,7 +10788,7 @@ async function runMechanicalChecks(options) {
|
|
|
10653
10788
|
statuses["check-docs"] = "warn";
|
|
10654
10789
|
localFindings.push({
|
|
10655
10790
|
tool: "check-docs",
|
|
10656
|
-
file:
|
|
10791
|
+
file: path25.join(projectRoot, "docs"),
|
|
10657
10792
|
message: err instanceof Error ? err.message : String(err),
|
|
10658
10793
|
severity: "warning"
|
|
10659
10794
|
});
|
|
@@ -10750,18 +10885,18 @@ function computeContextBudget(diffLines) {
|
|
|
10750
10885
|
return diffLines;
|
|
10751
10886
|
}
|
|
10752
10887
|
function isWithinProject(absPath, projectRoot) {
|
|
10753
|
-
const resolvedRoot =
|
|
10754
|
-
const resolvedPath =
|
|
10755
|
-
return resolvedPath.startsWith(resolvedRoot) || resolvedPath ===
|
|
10888
|
+
const resolvedRoot = path26.resolve(projectRoot) + path26.sep;
|
|
10889
|
+
const resolvedPath = path26.resolve(absPath);
|
|
10890
|
+
return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path26.resolve(projectRoot);
|
|
10756
10891
|
}
|
|
10757
10892
|
async function readContextFile(projectRoot, filePath, reason) {
|
|
10758
|
-
const absPath =
|
|
10893
|
+
const absPath = path26.isAbsolute(filePath) ? filePath : path26.join(projectRoot, filePath);
|
|
10759
10894
|
if (!isWithinProject(absPath, projectRoot)) return null;
|
|
10760
10895
|
const result = await readFileContent(absPath);
|
|
10761
10896
|
if (!result.ok) return null;
|
|
10762
10897
|
const content = result.value;
|
|
10763
10898
|
const lines = content.split("\n").length;
|
|
10764
|
-
const relPath2 =
|
|
10899
|
+
const relPath2 = path26.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
|
|
10765
10900
|
return { path: relPath2, content, reason, lines };
|
|
10766
10901
|
}
|
|
10767
10902
|
function extractImportSources2(content) {
|
|
@@ -10776,18 +10911,18 @@ function extractImportSources2(content) {
|
|
|
10776
10911
|
}
|
|
10777
10912
|
async function resolveImportPath2(projectRoot, fromFile, importSource) {
|
|
10778
10913
|
if (!importSource.startsWith(".")) return null;
|
|
10779
|
-
const fromDir =
|
|
10780
|
-
const basePath =
|
|
10914
|
+
const fromDir = path26.dirname(path26.join(projectRoot, fromFile));
|
|
10915
|
+
const basePath = path26.resolve(fromDir, importSource);
|
|
10781
10916
|
if (!isWithinProject(basePath, projectRoot)) return null;
|
|
10782
10917
|
const relBase = relativePosix(projectRoot, basePath);
|
|
10783
10918
|
const candidates = [
|
|
10784
10919
|
relBase + ".ts",
|
|
10785
10920
|
relBase + ".tsx",
|
|
10786
10921
|
relBase + ".mts",
|
|
10787
|
-
|
|
10922
|
+
path26.join(relBase, "index.ts")
|
|
10788
10923
|
];
|
|
10789
10924
|
for (const candidate of candidates) {
|
|
10790
|
-
const absCandidate =
|
|
10925
|
+
const absCandidate = path26.join(projectRoot, candidate);
|
|
10791
10926
|
if (await fileExists(absCandidate)) {
|
|
10792
10927
|
return candidate;
|
|
10793
10928
|
}
|
|
@@ -10795,7 +10930,7 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
|
|
|
10795
10930
|
return null;
|
|
10796
10931
|
}
|
|
10797
10932
|
async function findTestFiles(projectRoot, sourceFile) {
|
|
10798
|
-
const baseName =
|
|
10933
|
+
const baseName = path26.basename(sourceFile, path26.extname(sourceFile));
|
|
10799
10934
|
const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
|
|
10800
10935
|
const results = await findFiles(pattern, projectRoot);
|
|
10801
10936
|
return results.map((f) => relativePosix(projectRoot, f));
|
|
@@ -11563,7 +11698,7 @@ function normalizePath(filePath, projectRoot) {
|
|
|
11563
11698
|
let normalized = filePath;
|
|
11564
11699
|
normalized = normalized.replace(/\\/g, "/");
|
|
11565
11700
|
const normalizedRoot = projectRoot.replace(/\\/g, "/");
|
|
11566
|
-
if (
|
|
11701
|
+
if (path27.isAbsolute(normalized)) {
|
|
11567
11702
|
const root = normalizedRoot.endsWith("/") ? normalizedRoot : normalizedRoot + "/";
|
|
11568
11703
|
if (normalized.startsWith(root)) {
|
|
11569
11704
|
normalized = normalized.slice(root.length);
|
|
@@ -11575,12 +11710,12 @@ function normalizePath(filePath, projectRoot) {
|
|
|
11575
11710
|
return normalized;
|
|
11576
11711
|
}
|
|
11577
11712
|
function resolveImportPath22(currentFile, importPath) {
|
|
11578
|
-
const dir =
|
|
11579
|
-
let resolved =
|
|
11713
|
+
const dir = path27.dirname(currentFile);
|
|
11714
|
+
let resolved = path27.join(dir, importPath).replace(/\\/g, "/");
|
|
11580
11715
|
if (!resolved.match(/\.(ts|tsx|js|jsx)$/)) {
|
|
11581
11716
|
resolved += ".ts";
|
|
11582
11717
|
}
|
|
11583
|
-
return
|
|
11718
|
+
return path27.normalize(resolved).replace(/\\/g, "/");
|
|
11584
11719
|
}
|
|
11585
11720
|
function enqueueImports(content, current, visited, queue, maxDepth) {
|
|
11586
11721
|
const importRegex = /import\s+.*?from\s+['"]([^'"]+)['"]/g;
|
|
@@ -11612,7 +11747,7 @@ function isMechanicallyExcluded(finding, exclusionSet, projectRoot) {
|
|
|
11612
11747
|
const normalizedFile = normalizePath(finding.file, projectRoot);
|
|
11613
11748
|
if (exclusionSet.isExcluded(normalizedFile, finding.lineRange)) return true;
|
|
11614
11749
|
if (exclusionSet.isExcluded(finding.file, finding.lineRange)) return true;
|
|
11615
|
-
const absoluteFile =
|
|
11750
|
+
const absoluteFile = path27.isAbsolute(finding.file) ? finding.file : path27.join(projectRoot, finding.file).replace(/\\/g, "/");
|
|
11616
11751
|
return exclusionSet.isExcluded(absoluteFile, finding.lineRange);
|
|
11617
11752
|
}
|
|
11618
11753
|
async function validateWithGraph(crossFileRefs, graph) {
|
|
@@ -12620,7 +12755,7 @@ function isRegression(from, to) {
|
|
|
12620
12755
|
}
|
|
12621
12756
|
function collectAutopilotStatuses(autopilotPath, featurePlans, allTaskStatuses) {
|
|
12622
12757
|
try {
|
|
12623
|
-
const raw =
|
|
12758
|
+
const raw = fs28.readFileSync(autopilotPath, "utf-8");
|
|
12624
12759
|
const autopilot = JSON.parse(raw);
|
|
12625
12760
|
if (!autopilot.phases) return;
|
|
12626
12761
|
const linkedPhases = autopilot.phases.filter(
|
|
@@ -12652,10 +12787,10 @@ function inferStatus(feature, projectPath, allFeatures) {
|
|
|
12652
12787
|
const featuresWithPlans = allFeatures.filter((f) => f.plans.length > 0);
|
|
12653
12788
|
const useRootState = featuresWithPlans.length <= 1;
|
|
12654
12789
|
if (useRootState) {
|
|
12655
|
-
const rootStatePath =
|
|
12656
|
-
if (
|
|
12790
|
+
const rootStatePath = path28.join(projectPath, ".harness", "state.json");
|
|
12791
|
+
if (fs28.existsSync(rootStatePath)) {
|
|
12657
12792
|
try {
|
|
12658
|
-
const raw =
|
|
12793
|
+
const raw = fs28.readFileSync(rootStatePath, "utf-8");
|
|
12659
12794
|
const state = JSON.parse(raw);
|
|
12660
12795
|
if (state.progress) {
|
|
12661
12796
|
for (const status of Object.values(state.progress)) {
|
|
@@ -12666,14 +12801,14 @@ function inferStatus(feature, projectPath, allFeatures) {
|
|
|
12666
12801
|
}
|
|
12667
12802
|
}
|
|
12668
12803
|
}
|
|
12669
|
-
const sessionsDir =
|
|
12670
|
-
if (
|
|
12804
|
+
const sessionsDir = path28.join(projectPath, ".harness", "sessions");
|
|
12805
|
+
if (fs28.existsSync(sessionsDir)) {
|
|
12671
12806
|
try {
|
|
12672
|
-
const sessionDirs =
|
|
12807
|
+
const sessionDirs = fs28.readdirSync(sessionsDir, { withFileTypes: true });
|
|
12673
12808
|
for (const entry of sessionDirs) {
|
|
12674
12809
|
if (!entry.isDirectory()) continue;
|
|
12675
|
-
const autopilotPath =
|
|
12676
|
-
if (!
|
|
12810
|
+
const autopilotPath = path28.join(sessionsDir, entry.name, "autopilot-state.json");
|
|
12811
|
+
if (!fs28.existsSync(autopilotPath)) continue;
|
|
12677
12812
|
collectAutopilotStatuses(autopilotPath, feature.plans, allTaskStatuses);
|
|
12678
12813
|
}
|
|
12679
12814
|
} catch {
|
|
@@ -12788,9 +12923,9 @@ function isValidTrackerShape(tracker) {
|
|
|
12788
12923
|
}
|
|
12789
12924
|
function loadTrackerSyncConfig(projectRoot) {
|
|
12790
12925
|
try {
|
|
12791
|
-
const configPath =
|
|
12792
|
-
if (!
|
|
12793
|
-
const raw =
|
|
12926
|
+
const configPath = path29.join(projectRoot, "harness.config.json");
|
|
12927
|
+
if (!fs29.existsSync(configPath)) return null;
|
|
12928
|
+
const raw = fs29.readFileSync(configPath, "utf-8");
|
|
12794
12929
|
const config = JSON.parse(raw);
|
|
12795
12930
|
const tracker = config.roadmap?.tracker;
|
|
12796
12931
|
if (!isValidTrackerShape(tracker)) return null;
|
|
@@ -12817,14 +12952,14 @@ function buildDedupIndex(tickets, config) {
|
|
|
12817
12952
|
}
|
|
12818
12953
|
return index;
|
|
12819
12954
|
}
|
|
12820
|
-
async function resolveExternalId(feature, milestone,
|
|
12955
|
+
async function resolveExternalId(feature, milestone, adapter2, dedupIndex, result) {
|
|
12821
12956
|
if (feature.externalId) return true;
|
|
12822
12957
|
const existing = dedupIndex.get(feature.name.toLowerCase());
|
|
12823
12958
|
if (existing) {
|
|
12824
12959
|
feature.externalId = existing.externalId;
|
|
12825
12960
|
return true;
|
|
12826
12961
|
}
|
|
12827
|
-
const createResult = await
|
|
12962
|
+
const createResult = await adapter2.createTicket(feature, milestone);
|
|
12828
12963
|
if (createResult.ok) {
|
|
12829
12964
|
feature.externalId = createResult.value.externalId;
|
|
12830
12965
|
result.created.push(createResult.value);
|
|
@@ -12833,7 +12968,7 @@ async function resolveExternalId(feature, milestone, adapter, dedupIndex, result
|
|
|
12833
12968
|
}
|
|
12834
12969
|
return false;
|
|
12835
12970
|
}
|
|
12836
|
-
async function syncToExternal(roadmap,
|
|
12971
|
+
async function syncToExternal(roadmap, adapter2, config, prefetchedTickets) {
|
|
12837
12972
|
const result = emptySyncResult();
|
|
12838
12973
|
const dedupIndex = buildDedupIndex(prefetchedTickets, config);
|
|
12839
12974
|
for (const milestone of roadmap.milestones) {
|
|
@@ -12841,12 +12976,12 @@ async function syncToExternal(roadmap, adapter, config, prefetchedTickets) {
|
|
|
12841
12976
|
const shouldUpdate = await resolveExternalId(
|
|
12842
12977
|
feature,
|
|
12843
12978
|
milestone.name,
|
|
12844
|
-
|
|
12979
|
+
adapter2,
|
|
12845
12980
|
dedupIndex,
|
|
12846
12981
|
result
|
|
12847
12982
|
);
|
|
12848
12983
|
if (!shouldUpdate) continue;
|
|
12849
|
-
const updateResult = await
|
|
12984
|
+
const updateResult = await adapter2.updateTicket(feature.externalId, feature, milestone.name);
|
|
12850
12985
|
if (updateResult.ok) {
|
|
12851
12986
|
result.updated.push(feature.externalId);
|
|
12852
12987
|
} else {
|
|
@@ -12872,7 +13007,7 @@ function applyTicketToFeature(ticketState, feature, config, forceSync, result) {
|
|
|
12872
13007
|
if (!forceSync && feature.status === "blocked" && newStatus === "planned") return;
|
|
12873
13008
|
feature.status = newStatus;
|
|
12874
13009
|
}
|
|
12875
|
-
async function syncFromExternal(roadmap,
|
|
13010
|
+
async function syncFromExternal(roadmap, adapter2, config, options, prefetchedTickets) {
|
|
12876
13011
|
const result = emptySyncResult();
|
|
12877
13012
|
const forceSync = options?.forceSync ?? false;
|
|
12878
13013
|
const featureByExternalId = /* @__PURE__ */ new Map();
|
|
@@ -12888,7 +13023,7 @@ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTic
|
|
|
12888
13023
|
if (prefetchedTickets) {
|
|
12889
13024
|
tickets = prefetchedTickets;
|
|
12890
13025
|
} else {
|
|
12891
|
-
const fetchResult = await
|
|
13026
|
+
const fetchResult = await adapter2.fetchAllTickets();
|
|
12892
13027
|
if (!fetchResult.ok) {
|
|
12893
13028
|
result.errors.push({ featureOrId: "*", error: fetchResult.error });
|
|
12894
13029
|
return result;
|
|
@@ -12902,7 +13037,7 @@ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTic
|
|
|
12902
13037
|
}
|
|
12903
13038
|
return result;
|
|
12904
13039
|
}
|
|
12905
|
-
async function fullSync(roadmapPath,
|
|
13040
|
+
async function fullSync(roadmapPath, adapter2, config, options) {
|
|
12906
13041
|
const previousSync = syncMutex;
|
|
12907
13042
|
let releaseMutex;
|
|
12908
13043
|
syncMutex = new Promise((resolve8) => {
|
|
@@ -12910,7 +13045,7 @@ async function fullSync(roadmapPath, adapter, config, options) {
|
|
|
12910
13045
|
});
|
|
12911
13046
|
await previousSync;
|
|
12912
13047
|
try {
|
|
12913
|
-
const raw =
|
|
13048
|
+
const raw = fs30.readFileSync(roadmapPath, "utf-8");
|
|
12914
13049
|
const parseResult = parseRoadmap(raw);
|
|
12915
13050
|
if (!parseResult.ok) {
|
|
12916
13051
|
return {
|
|
@@ -12919,11 +13054,11 @@ async function fullSync(roadmapPath, adapter, config, options) {
|
|
|
12919
13054
|
};
|
|
12920
13055
|
}
|
|
12921
13056
|
const roadmap = parseResult.value;
|
|
12922
|
-
const fetchResult = await
|
|
13057
|
+
const fetchResult = await adapter2.fetchAllTickets();
|
|
12923
13058
|
const tickets = fetchResult.ok ? fetchResult.value : void 0;
|
|
12924
|
-
const pushResult = await syncToExternal(roadmap,
|
|
12925
|
-
const pullResult = await syncFromExternal(roadmap,
|
|
12926
|
-
|
|
13059
|
+
const pushResult = await syncToExternal(roadmap, adapter2, config, tickets);
|
|
13060
|
+
const pullResult = await syncFromExternal(roadmap, adapter2, config, options);
|
|
13061
|
+
fs30.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
|
|
12927
13062
|
return {
|
|
12928
13063
|
created: pushResult.created,
|
|
12929
13064
|
updated: pushResult.updated,
|
|
@@ -13045,7 +13180,7 @@ function assignFeature(roadmap, feature, assignee, date) {
|
|
|
13045
13180
|
}
|
|
13046
13181
|
function getStatePath() {
|
|
13047
13182
|
const home = process.env["HOME"] || os.homedir();
|
|
13048
|
-
return
|
|
13183
|
+
return path32.join(home, ".harness", "update-check.json");
|
|
13049
13184
|
}
|
|
13050
13185
|
function isUpdateCheckEnabled(configInterval) {
|
|
13051
13186
|
if (process.env["HARNESS_NO_UPDATE_CHECK"] === "1") return false;
|
|
@@ -13058,7 +13193,7 @@ function shouldRunCheck(state, intervalMs) {
|
|
|
13058
13193
|
}
|
|
13059
13194
|
function readCheckState() {
|
|
13060
13195
|
try {
|
|
13061
|
-
const raw =
|
|
13196
|
+
const raw = fs33.readFileSync(getStatePath(), "utf-8");
|
|
13062
13197
|
const parsed = JSON.parse(raw);
|
|
13063
13198
|
if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
|
|
13064
13199
|
const state = parsed;
|
|
@@ -13075,7 +13210,7 @@ function readCheckState() {
|
|
|
13075
13210
|
}
|
|
13076
13211
|
function spawnBackgroundCheck(currentVersion) {
|
|
13077
13212
|
const statePath = getStatePath();
|
|
13078
|
-
const stateDir =
|
|
13213
|
+
const stateDir = path32.dirname(statePath);
|
|
13079
13214
|
const script = `
|
|
13080
13215
|
const { execSync } = require('child_process');
|
|
13081
13216
|
const fs = require('fs');
|
|
@@ -13318,14 +13453,14 @@ function getModelPrice(model, dataset) {
|
|
|
13318
13453
|
return pricing;
|
|
13319
13454
|
}
|
|
13320
13455
|
function getCachePath(projectRoot) {
|
|
13321
|
-
return
|
|
13456
|
+
return path33.join(projectRoot, ".harness", "cache", "pricing.json");
|
|
13322
13457
|
}
|
|
13323
13458
|
function getStalenessMarkerPath(projectRoot) {
|
|
13324
|
-
return
|
|
13459
|
+
return path33.join(projectRoot, ".harness", "cache", "staleness-marker.json");
|
|
13325
13460
|
}
|
|
13326
13461
|
async function readDiskCache(projectRoot) {
|
|
13327
13462
|
try {
|
|
13328
|
-
const raw = await
|
|
13463
|
+
const raw = await fs34.readFile(getCachePath(projectRoot), "utf-8");
|
|
13329
13464
|
return JSON.parse(raw);
|
|
13330
13465
|
} catch {
|
|
13331
13466
|
return null;
|
|
@@ -13333,8 +13468,8 @@ async function readDiskCache(projectRoot) {
|
|
|
13333
13468
|
}
|
|
13334
13469
|
async function writeDiskCache(projectRoot, data) {
|
|
13335
13470
|
const cachePath = getCachePath(projectRoot);
|
|
13336
|
-
await
|
|
13337
|
-
await
|
|
13471
|
+
await fs34.mkdir(path33.dirname(cachePath), { recursive: true });
|
|
13472
|
+
await fs34.writeFile(cachePath, JSON.stringify(data, null, 2));
|
|
13338
13473
|
}
|
|
13339
13474
|
async function fetchFromNetwork() {
|
|
13340
13475
|
try {
|
|
@@ -13361,7 +13496,7 @@ function loadFallbackDataset() {
|
|
|
13361
13496
|
async function checkAndWarnStaleness(projectRoot) {
|
|
13362
13497
|
const markerPath = getStalenessMarkerPath(projectRoot);
|
|
13363
13498
|
try {
|
|
13364
|
-
const raw = await
|
|
13499
|
+
const raw = await fs34.readFile(markerPath, "utf-8");
|
|
13365
13500
|
const marker = JSON.parse(raw);
|
|
13366
13501
|
const firstUse = new Date(marker.firstFallbackUse).getTime();
|
|
13367
13502
|
const now = Date.now();
|
|
@@ -13373,8 +13508,8 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
13373
13508
|
}
|
|
13374
13509
|
} catch {
|
|
13375
13510
|
try {
|
|
13376
|
-
await
|
|
13377
|
-
await
|
|
13511
|
+
await fs34.mkdir(path33.dirname(markerPath), { recursive: true });
|
|
13512
|
+
await fs34.writeFile(
|
|
13378
13513
|
markerPath,
|
|
13379
13514
|
JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
|
|
13380
13515
|
);
|
|
@@ -13384,7 +13519,7 @@ async function checkAndWarnStaleness(projectRoot) {
|
|
|
13384
13519
|
}
|
|
13385
13520
|
async function clearStalenessMarker(projectRoot) {
|
|
13386
13521
|
try {
|
|
13387
|
-
await
|
|
13522
|
+
await fs34.unlink(getStalenessMarkerPath(projectRoot));
|
|
13388
13523
|
} catch {
|
|
13389
13524
|
}
|
|
13390
13525
|
}
|
|
@@ -13621,10 +13756,10 @@ function parseLine(line, lineNumber) {
|
|
|
13621
13756
|
return record;
|
|
13622
13757
|
}
|
|
13623
13758
|
function readCostRecords(projectRoot) {
|
|
13624
|
-
const costsFile =
|
|
13759
|
+
const costsFile = path34.join(projectRoot, ".harness", "metrics", "costs.jsonl");
|
|
13625
13760
|
let raw;
|
|
13626
13761
|
try {
|
|
13627
|
-
raw =
|
|
13762
|
+
raw = fs35.readFileSync(costsFile, "utf-8");
|
|
13628
13763
|
} catch {
|
|
13629
13764
|
return [];
|
|
13630
13765
|
}
|
|
@@ -13674,7 +13809,7 @@ function parseCCLine(line, filePath, lineNumber) {
|
|
|
13674
13809
|
entry = JSON.parse(line);
|
|
13675
13810
|
} catch {
|
|
13676
13811
|
console.warn(
|
|
13677
|
-
`[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${
|
|
13812
|
+
`[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path35.basename(filePath)}`
|
|
13678
13813
|
);
|
|
13679
13814
|
return null;
|
|
13680
13815
|
}
|
|
@@ -13688,7 +13823,7 @@ function parseCCLine(line, filePath, lineNumber) {
|
|
|
13688
13823
|
function readCCFile(filePath) {
|
|
13689
13824
|
let raw;
|
|
13690
13825
|
try {
|
|
13691
|
-
raw =
|
|
13826
|
+
raw = fs36.readFileSync(filePath, "utf-8");
|
|
13692
13827
|
} catch {
|
|
13693
13828
|
return [];
|
|
13694
13829
|
}
|
|
@@ -13710,10 +13845,10 @@ function readCCFile(filePath) {
|
|
|
13710
13845
|
}
|
|
13711
13846
|
function parseCCRecords() {
|
|
13712
13847
|
const homeDir = process.env.HOME ?? os2.homedir();
|
|
13713
|
-
const projectsDir =
|
|
13848
|
+
const projectsDir = path35.join(homeDir, ".claude", "projects");
|
|
13714
13849
|
let projectDirs;
|
|
13715
13850
|
try {
|
|
13716
|
-
projectDirs =
|
|
13851
|
+
projectDirs = fs36.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path35.join(projectsDir, d.name));
|
|
13717
13852
|
} catch {
|
|
13718
13853
|
return [];
|
|
13719
13854
|
}
|
|
@@ -13721,7 +13856,7 @@ function parseCCRecords() {
|
|
|
13721
13856
|
for (const dir of projectDirs) {
|
|
13722
13857
|
let files;
|
|
13723
13858
|
try {
|
|
13724
|
-
files =
|
|
13859
|
+
files = fs36.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path35.join(dir, f));
|
|
13725
13860
|
} catch {
|
|
13726
13861
|
continue;
|
|
13727
13862
|
}
|
|
@@ -13749,10 +13884,10 @@ function parseLine2(line, lineNumber) {
|
|
|
13749
13884
|
}
|
|
13750
13885
|
}
|
|
13751
13886
|
function readAdoptionRecords(projectRoot) {
|
|
13752
|
-
const adoptionFile =
|
|
13887
|
+
const adoptionFile = path36.join(projectRoot, ".harness", "metrics", "adoption.jsonl");
|
|
13753
13888
|
let raw;
|
|
13754
13889
|
try {
|
|
13755
|
-
raw =
|
|
13890
|
+
raw = fs37.readFileSync(adoptionFile, "utf-8");
|
|
13756
13891
|
} catch {
|
|
13757
13892
|
return [];
|
|
13758
13893
|
}
|
|
@@ -13900,25 +14035,25 @@ function resolveStability(contentType) {
|
|
|
13900
14035
|
return STABILITY_LOOKUP[contentType] ?? "ephemeral";
|
|
13901
14036
|
}
|
|
13902
14037
|
function getOrCreateInstallId(projectRoot) {
|
|
13903
|
-
const harnessDir =
|
|
13904
|
-
const installIdFile =
|
|
14038
|
+
const harnessDir = path37.join(projectRoot, ".harness");
|
|
14039
|
+
const installIdFile = path37.join(harnessDir, ".install-id");
|
|
13905
14040
|
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
13906
14041
|
try {
|
|
13907
|
-
const existing =
|
|
14042
|
+
const existing = fs38.readFileSync(installIdFile, "utf-8").trim();
|
|
13908
14043
|
if (UUID_V4_RE.test(existing)) {
|
|
13909
14044
|
return existing;
|
|
13910
14045
|
}
|
|
13911
14046
|
} catch {
|
|
13912
14047
|
}
|
|
13913
14048
|
const id = crypto4.randomUUID();
|
|
13914
|
-
|
|
13915
|
-
|
|
14049
|
+
fs38.mkdirSync(harnessDir, { recursive: true });
|
|
14050
|
+
fs38.writeFileSync(installIdFile, id, { encoding: "utf-8", mode: 384 });
|
|
13916
14051
|
return id;
|
|
13917
14052
|
}
|
|
13918
14053
|
function parseIdentityFromTelemetryFile(filePath) {
|
|
13919
14054
|
const identity = {};
|
|
13920
14055
|
try {
|
|
13921
|
-
const raw =
|
|
14056
|
+
const raw = fs39.readFileSync(filePath, "utf-8");
|
|
13922
14057
|
const parsed = JSON.parse(raw);
|
|
13923
14058
|
const src = parsed?.identity;
|
|
13924
14059
|
if (!src || typeof src !== "object") return identity;
|
|
@@ -13931,7 +14066,7 @@ function parseIdentityFromTelemetryFile(filePath) {
|
|
|
13931
14066
|
}
|
|
13932
14067
|
function readProjectNameFallback(configPath) {
|
|
13933
14068
|
try {
|
|
13934
|
-
const raw =
|
|
14069
|
+
const raw = fs39.readFileSync(configPath, "utf-8");
|
|
13935
14070
|
const config = JSON.parse(raw);
|
|
13936
14071
|
return typeof config?.name === "string" ? config.name : void 0;
|
|
13937
14072
|
} catch {
|
|
@@ -13952,10 +14087,10 @@ function readGitAliasFallback(cwd) {
|
|
|
13952
14087
|
}
|
|
13953
14088
|
}
|
|
13954
14089
|
function readIdentity(projectRoot) {
|
|
13955
|
-
const filePath =
|
|
14090
|
+
const filePath = path38.join(projectRoot, ".harness", "telemetry.json");
|
|
13956
14091
|
const identity = parseIdentityFromTelemetryFile(filePath);
|
|
13957
14092
|
if (!identity.project) {
|
|
13958
|
-
const fallbackProject = readProjectNameFallback(
|
|
14093
|
+
const fallbackProject = readProjectNameFallback(path38.join(projectRoot, "harness.config.json"));
|
|
13959
14094
|
if (fallbackProject) identity.project = fallbackProject;
|
|
13960
14095
|
}
|
|
13961
14096
|
if (!identity.alias) {
|
|
@@ -14025,7 +14160,557 @@ async function send(events, apiKey) {
|
|
|
14025
14160
|
}
|
|
14026
14161
|
}
|
|
14027
14162
|
}
|
|
14028
|
-
|
|
14163
|
+
function acquireCompoundLock(category, opts = {}) {
|
|
14164
|
+
if (!KNOWN_CATEGORIES.has(category)) {
|
|
14165
|
+
throw new Error(
|
|
14166
|
+
`Unknown category "${category}". Must be one of: ${[...KNOWN_CATEGORIES].join(", ")}`
|
|
14167
|
+
);
|
|
14168
|
+
}
|
|
14169
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
14170
|
+
const lockDir = path39.join(cwd, ".harness", "locks");
|
|
14171
|
+
fs40.mkdirSync(lockDir, { recursive: true });
|
|
14172
|
+
const lockPath = path39.join(lockDir, `compound-${category}.lock`);
|
|
14173
|
+
let fd;
|
|
14174
|
+
try {
|
|
14175
|
+
fd = fs40.openSync(lockPath, "wx");
|
|
14176
|
+
} catch (e) {
|
|
14177
|
+
const err = e;
|
|
14178
|
+
if (err.code === "EEXIST") {
|
|
14179
|
+
const holderPid = readHolderPid(lockPath);
|
|
14180
|
+
throw new CompoundLockHeldError(category, holderPid, lockPath);
|
|
14181
|
+
}
|
|
14182
|
+
throw err;
|
|
14183
|
+
}
|
|
14184
|
+
fs40.writeSync(fd, String(process.pid));
|
|
14185
|
+
fs40.closeSync(fd);
|
|
14186
|
+
let released = false;
|
|
14187
|
+
const release = () => {
|
|
14188
|
+
if (released) return;
|
|
14189
|
+
released = true;
|
|
14190
|
+
try {
|
|
14191
|
+
fs40.unlinkSync(lockPath);
|
|
14192
|
+
} catch {
|
|
14193
|
+
}
|
|
14194
|
+
process.removeListener("exit", onExit);
|
|
14195
|
+
process.removeListener("SIGINT", onSignal);
|
|
14196
|
+
process.removeListener("SIGTERM", onSignal);
|
|
14197
|
+
process.removeListener("uncaughtException", onUncaught);
|
|
14198
|
+
};
|
|
14199
|
+
const onExit = () => release();
|
|
14200
|
+
const onSignal = (sig) => {
|
|
14201
|
+
release();
|
|
14202
|
+
process.kill(process.pid, sig);
|
|
14203
|
+
};
|
|
14204
|
+
const onUncaught = (err) => {
|
|
14205
|
+
release();
|
|
14206
|
+
console.error(err && err.stack ? err.stack : err);
|
|
14207
|
+
process.exit(1);
|
|
14208
|
+
};
|
|
14209
|
+
process.once("exit", onExit);
|
|
14210
|
+
process.once("SIGINT", onSignal);
|
|
14211
|
+
process.once("SIGTERM", onSignal);
|
|
14212
|
+
process.once("uncaughtException", onUncaught);
|
|
14213
|
+
return { category, lockPath, release };
|
|
14214
|
+
}
|
|
14215
|
+
function readHolderPid(lockPath) {
|
|
14216
|
+
try {
|
|
14217
|
+
const raw = fs40.readFileSync(lockPath, "utf-8").trim();
|
|
14218
|
+
const n = Number.parseInt(raw, 10);
|
|
14219
|
+
return Number.isFinite(n) ? n : -1;
|
|
14220
|
+
} catch {
|
|
14221
|
+
return -1;
|
|
14222
|
+
}
|
|
14223
|
+
}
|
|
14224
|
+
function isSanitizedResult(value) {
|
|
14225
|
+
if (!value || typeof value !== "object") return false;
|
|
14226
|
+
const v = value;
|
|
14227
|
+
if (!v.fields || typeof v.fields !== "object") return false;
|
|
14228
|
+
for (const k of Object.keys(v.fields)) {
|
|
14229
|
+
if (!ALLOWED_SET.has(k)) return false;
|
|
14230
|
+
if (PII_FIELD_DENYLIST.test(k)) return false;
|
|
14231
|
+
}
|
|
14232
|
+
if (!v.distributions || typeof v.distributions !== "object") return false;
|
|
14233
|
+
return true;
|
|
14234
|
+
}
|
|
14235
|
+
function assertSanitized(value) {
|
|
14236
|
+
if (!isSanitizedResult(value)) {
|
|
14237
|
+
throw new Error("PII boundary violated: result is not a SanitizedResult");
|
|
14238
|
+
}
|
|
14239
|
+
}
|
|
14240
|
+
function writePulseConfig(config, opts) {
|
|
14241
|
+
PulseConfigSchema.parse(config);
|
|
14242
|
+
if (!fs41.existsSync(opts.configPath)) {
|
|
14243
|
+
throw new Error(`harness.config.json not found at ${opts.configPath}`);
|
|
14244
|
+
}
|
|
14245
|
+
const raw = fs41.readFileSync(opts.configPath, "utf-8");
|
|
14246
|
+
let parsed;
|
|
14247
|
+
try {
|
|
14248
|
+
parsed = JSON.parse(raw);
|
|
14249
|
+
} catch (e) {
|
|
14250
|
+
throw new Error(`Invalid JSON in ${opts.configPath}: ${e.message}`, { cause: e });
|
|
14251
|
+
}
|
|
14252
|
+
const bakPath = `${opts.configPath}.bak`;
|
|
14253
|
+
if (!opts.skipBackup && !fs41.existsSync(bakPath)) {
|
|
14254
|
+
fs41.writeFileSync(bakPath, raw, "utf-8");
|
|
14255
|
+
}
|
|
14256
|
+
parsed.pulse = config;
|
|
14257
|
+
const serialized = JSON.stringify(parsed, null, 2) + "\n";
|
|
14258
|
+
const tmpPath = `${opts.configPath}.tmp-${process.pid}`;
|
|
14259
|
+
fs41.writeFileSync(tmpPath, serialized, "utf-8");
|
|
14260
|
+
try {
|
|
14261
|
+
fs41.renameSync(tmpPath, opts.configPath);
|
|
14262
|
+
} catch (e) {
|
|
14263
|
+
try {
|
|
14264
|
+
fs41.unlinkSync(tmpPath);
|
|
14265
|
+
} catch {
|
|
14266
|
+
}
|
|
14267
|
+
throw e;
|
|
14268
|
+
}
|
|
14269
|
+
}
|
|
14270
|
+
function seedFromStrategy(opts = {}) {
|
|
14271
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
14272
|
+
const strategyPath = path40.join(cwd, "STRATEGY.md");
|
|
14273
|
+
const warnings = [];
|
|
14274
|
+
if (!fs42.existsSync(strategyPath)) {
|
|
14275
|
+
return { name: null, keyMetrics: [], warnings: ["STRATEGY.md not found"] };
|
|
14276
|
+
}
|
|
14277
|
+
const raw = fs42.readFileSync(strategyPath, "utf-8");
|
|
14278
|
+
let name = null;
|
|
14279
|
+
const fmMatch = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
|
|
14280
|
+
const fm = fmMatch?.[1];
|
|
14281
|
+
if (fm !== void 0) {
|
|
14282
|
+
const nameMatch = /^name:\s*['"]?([^'"\n]+)['"]?\s*$/m.exec(fm);
|
|
14283
|
+
const nameCapture = nameMatch?.[1];
|
|
14284
|
+
if (nameCapture !== void 0) {
|
|
14285
|
+
name = nameCapture.trim();
|
|
14286
|
+
}
|
|
14287
|
+
}
|
|
14288
|
+
if (name === null) {
|
|
14289
|
+
const h1 = /^#\s+(.+)$/m.exec(raw);
|
|
14290
|
+
const h1Capture = h1?.[1];
|
|
14291
|
+
if (h1Capture !== void 0) {
|
|
14292
|
+
name = h1Capture.trim();
|
|
14293
|
+
warnings.push("STRATEGY.md frontmatter missing name; used H1 fallback");
|
|
14294
|
+
}
|
|
14295
|
+
}
|
|
14296
|
+
const keyMetrics = [];
|
|
14297
|
+
const headerMatch = /^##\s+Key metrics\s*$/m.exec(raw);
|
|
14298
|
+
if (headerMatch && headerMatch.index !== void 0) {
|
|
14299
|
+
const startIdx = headerMatch.index + headerMatch[0].length;
|
|
14300
|
+
const after = raw.slice(startIdx);
|
|
14301
|
+
const stopMatch = /^(#{1,3})\s+/m.exec(after);
|
|
14302
|
+
const block = stopMatch ? after.slice(0, stopMatch.index) : after;
|
|
14303
|
+
for (const line of block.split("\n")) {
|
|
14304
|
+
const m = /^[-*]\s+(.+)$/.exec(line.trim());
|
|
14305
|
+
const capture = m?.[1];
|
|
14306
|
+
if (capture !== void 0) keyMetrics.push(capture.trim());
|
|
14307
|
+
}
|
|
14308
|
+
} else {
|
|
14309
|
+
warnings.push("STRATEGY.md is missing a `## Key metrics` section");
|
|
14310
|
+
}
|
|
14311
|
+
return { name, keyMetrics, warnings };
|
|
14312
|
+
}
|
|
14313
|
+
function registerPulseAdapter(name, adapter2) {
|
|
14314
|
+
if (!adapter2 || typeof adapter2 !== "object") {
|
|
14315
|
+
throw new TypeError(`Pulse adapter "${name}" must be an object with query and sanitize.`);
|
|
14316
|
+
}
|
|
14317
|
+
if (typeof adapter2.query !== "function") {
|
|
14318
|
+
throw new TypeError(`Pulse adapter "${name}" is missing required field: query`);
|
|
14319
|
+
}
|
|
14320
|
+
if (typeof adapter2.sanitize !== "function") {
|
|
14321
|
+
throw new TypeError(`Pulse adapter "${name}" is missing required field: sanitize`);
|
|
14322
|
+
}
|
|
14323
|
+
if (REGISTRY.has(name)) {
|
|
14324
|
+
throw new PulseAdapterAlreadyRegisteredError(name);
|
|
14325
|
+
}
|
|
14326
|
+
REGISTRY.set(name, adapter2);
|
|
14327
|
+
}
|
|
14328
|
+
function getPulseAdapter(name) {
|
|
14329
|
+
return REGISTRY.get(name);
|
|
14330
|
+
}
|
|
14331
|
+
function listPulseAdapters() {
|
|
14332
|
+
return [...REGISTRY.keys()].sort();
|
|
14333
|
+
}
|
|
14334
|
+
function clearPulseAdapters() {
|
|
14335
|
+
REGISTRY.clear();
|
|
14336
|
+
}
|
|
14337
|
+
function registerMockAdapter() {
|
|
14338
|
+
if (listPulseAdapters().includes(MOCK_ADAPTER_NAME)) return;
|
|
14339
|
+
registerPulseAdapter(MOCK_ADAPTER_NAME, adapter);
|
|
14340
|
+
}
|
|
14341
|
+
function parseLookback(input) {
|
|
14342
|
+
const match = LOOKBACK_RE.exec(input);
|
|
14343
|
+
if (!match) {
|
|
14344
|
+
throw new Error(`Invalid lookback "${input}": expected format like "24h" or "7d"`);
|
|
14345
|
+
}
|
|
14346
|
+
const n = Number(match[1]);
|
|
14347
|
+
const unit = match[2];
|
|
14348
|
+
return unit === "h" ? n * 60 * 60 * 1e3 : n * 24 * 60 * 60 * 1e3;
|
|
14349
|
+
}
|
|
14350
|
+
function computeWindow(now, lookback, bufferMinutes = 15) {
|
|
14351
|
+
const lookbackMs = parseLookback(lookback);
|
|
14352
|
+
const bufferMs = bufferMinutes * 60 * 1e3;
|
|
14353
|
+
const end = new Date(now.getTime() - bufferMs);
|
|
14354
|
+
const start = new Date(end.getTime() - lookbackMs);
|
|
14355
|
+
return { start, end };
|
|
14356
|
+
}
|
|
14357
|
+
async function querySource(name, window) {
|
|
14358
|
+
const adapter2 = getPulseAdapter(name);
|
|
14359
|
+
if (!adapter2) {
|
|
14360
|
+
return {
|
|
14361
|
+
ok: false,
|
|
14362
|
+
skipKind: "no-adapter",
|
|
14363
|
+
reason: `no adapter registered for "${name}"`
|
|
14364
|
+
};
|
|
14365
|
+
}
|
|
14366
|
+
let sanitized;
|
|
14367
|
+
try {
|
|
14368
|
+
const raw = await adapter2.query(window);
|
|
14369
|
+
sanitized = adapter2.sanitize(raw);
|
|
14370
|
+
} catch (err) {
|
|
14371
|
+
return {
|
|
14372
|
+
ok: false,
|
|
14373
|
+
skipKind: "query-failure",
|
|
14374
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
14375
|
+
};
|
|
14376
|
+
}
|
|
14377
|
+
try {
|
|
14378
|
+
assertSanitized(sanitized);
|
|
14379
|
+
} catch (err) {
|
|
14380
|
+
return {
|
|
14381
|
+
ok: false,
|
|
14382
|
+
skipKind: "pii-violation",
|
|
14383
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
14384
|
+
};
|
|
14385
|
+
}
|
|
14386
|
+
return { ok: true, result: sanitized };
|
|
14387
|
+
}
|
|
14388
|
+
async function runPulse(config, window) {
|
|
14389
|
+
const startedAt = Date.now();
|
|
14390
|
+
const sources = [];
|
|
14391
|
+
const sourcesQueried = [];
|
|
14392
|
+
const sourcesSkipped = [];
|
|
14393
|
+
const parallelSlots = [
|
|
14394
|
+
["analytics", config.sources.analytics],
|
|
14395
|
+
["tracing", config.sources.tracing],
|
|
14396
|
+
["payments", config.sources.payments]
|
|
14397
|
+
];
|
|
14398
|
+
const parallelEntries = parallelSlots.filter(
|
|
14399
|
+
(slot) => slot[1] != null
|
|
14400
|
+
);
|
|
14401
|
+
const parallelResults = await Promise.all(
|
|
14402
|
+
parallelEntries.map(([kind, n]) => querySource(n, window).then((r) => [kind, n, r]))
|
|
14403
|
+
);
|
|
14404
|
+
for (const [kind, name, r] of parallelResults) {
|
|
14405
|
+
if (r.ok) {
|
|
14406
|
+
sources.push({ kind, name, result: r.result });
|
|
14407
|
+
sourcesQueried.push(name);
|
|
14408
|
+
} else {
|
|
14409
|
+
sourcesSkipped.push({ name, kind, skipKind: r.skipKind, reason: r.reason });
|
|
14410
|
+
}
|
|
14411
|
+
}
|
|
14412
|
+
if (config.sources.db.enabled && config.sources.db.source) {
|
|
14413
|
+
const name = config.sources.db.source;
|
|
14414
|
+
const r = await querySource(name, window);
|
|
14415
|
+
if (r.ok) {
|
|
14416
|
+
sources.push({ kind: "db", name, result: r.result });
|
|
14417
|
+
sourcesQueried.push(name);
|
|
14418
|
+
} else {
|
|
14419
|
+
sourcesSkipped.push({ name, kind: "db", skipKind: r.skipKind, reason: r.reason });
|
|
14420
|
+
}
|
|
14421
|
+
}
|
|
14422
|
+
return { sources, sourcesQueried, sourcesSkipped, durationMs: Date.now() - startedAt };
|
|
14423
|
+
}
|
|
14424
|
+
function loadTemplate() {
|
|
14425
|
+
try {
|
|
14426
|
+
const url = import.meta?.url;
|
|
14427
|
+
if (!url) return INLINE_TEMPLATE;
|
|
14428
|
+
const here = dirname18(fileURLToPath(url));
|
|
14429
|
+
return readFileSync36(join572(here, "template.md"), "utf-8");
|
|
14430
|
+
} catch {
|
|
14431
|
+
return INLINE_TEMPLATE;
|
|
14432
|
+
}
|
|
14433
|
+
}
|
|
14434
|
+
function totalCount(s) {
|
|
14435
|
+
const c = s.fields.count;
|
|
14436
|
+
return typeof c === "number" ? c : 0;
|
|
14437
|
+
}
|
|
14438
|
+
function buildHeadlines(r) {
|
|
14439
|
+
const total = r.sources.reduce((sum, s) => sum + totalCount(s.result), 0);
|
|
14440
|
+
return [
|
|
14441
|
+
`- ${r.sourcesQueried.length} source(s) queried in ${r.durationMs}ms`,
|
|
14442
|
+
`- ${total} total events recorded`,
|
|
14443
|
+
`- ${r.sourcesSkipped.length} source(s) skipped`
|
|
14444
|
+
].join("\n");
|
|
14445
|
+
}
|
|
14446
|
+
function buildUsage(r) {
|
|
14447
|
+
if (r.sources.length === 0) return "_(none)_";
|
|
14448
|
+
return r.sources.map((s) => {
|
|
14449
|
+
const name = s.result.fields.event_name ?? "unknown";
|
|
14450
|
+
const count = totalCount(s.result);
|
|
14451
|
+
return `- ${name}: count=${count}`;
|
|
14452
|
+
}).join("\n");
|
|
14453
|
+
}
|
|
14454
|
+
function buildSystemPerformance(r) {
|
|
14455
|
+
const tracing = r.sources.find((s) => s.kind === "tracing") ?? null;
|
|
14456
|
+
if (!tracing) return "_(no tracing source configured)_";
|
|
14457
|
+
const dist = tracing.result.distributions;
|
|
14458
|
+
const lines = Object.entries(dist).map(([k, v]) => `- ${k}: ${JSON.stringify(v)}`);
|
|
14459
|
+
return lines.length > 0 ? lines.join("\n") : "_(no distributions)_";
|
|
14460
|
+
}
|
|
14461
|
+
function buildFollowups(r) {
|
|
14462
|
+
if (r.sourcesSkipped.length === 0) return "_(none)_";
|
|
14463
|
+
return r.sourcesSkipped.map((s) => `- ${s.name} skipped: ${s.reason}`).join("\n");
|
|
14464
|
+
}
|
|
14465
|
+
function finalPiiSweep(text) {
|
|
14466
|
+
return text.split("\n").filter((l) => {
|
|
14467
|
+
if (l.startsWith("# ") || l.startsWith("## ")) return true;
|
|
14468
|
+
return !PII_LINE_RE.test(l);
|
|
14469
|
+
}).join("\n");
|
|
14470
|
+
}
|
|
14471
|
+
function truncateSection(lines, startIdx, endIdx) {
|
|
14472
|
+
const head = lines.slice(0, startIdx + 1);
|
|
14473
|
+
const section = lines.slice(startIdx + 1, endIdx);
|
|
14474
|
+
const tail = lines.slice(endIdx);
|
|
14475
|
+
let truncated = false;
|
|
14476
|
+
while (head.length + section.length + tail.length + (truncated ? 0 : 1) > MAX_LINES && section.length > 0) {
|
|
14477
|
+
section.pop();
|
|
14478
|
+
truncated = true;
|
|
14479
|
+
}
|
|
14480
|
+
if (truncated) section.push(TRUNCATION_MARKER2);
|
|
14481
|
+
return [...head, ...section, ...tail];
|
|
14482
|
+
}
|
|
14483
|
+
function truncateToFit(text) {
|
|
14484
|
+
let lines = text.split("\n");
|
|
14485
|
+
if (lines.length <= MAX_LINES) return text;
|
|
14486
|
+
const sections = [
|
|
14487
|
+
{ header: "## Followups" },
|
|
14488
|
+
{ header: "## System performance" },
|
|
14489
|
+
{ header: "## Usage" }
|
|
14490
|
+
];
|
|
14491
|
+
for (const { header } of sections) {
|
|
14492
|
+
if (lines.length <= MAX_LINES) break;
|
|
14493
|
+
const startIdx = lines.findIndex((l) => l === header || l.startsWith(`${header} `));
|
|
14494
|
+
if (startIdx < 0) continue;
|
|
14495
|
+
let endIdx = lines.length;
|
|
14496
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
14497
|
+
const line = lines[i];
|
|
14498
|
+
if (line !== void 0 && line.startsWith("## ")) {
|
|
14499
|
+
endIdx = i;
|
|
14500
|
+
break;
|
|
14501
|
+
}
|
|
14502
|
+
}
|
|
14503
|
+
lines = truncateSection(lines, startIdx, endIdx);
|
|
14504
|
+
}
|
|
14505
|
+
if (lines.length > MAX_LINES) lines = lines.slice(0, MAX_LINES);
|
|
14506
|
+
return lines.join("\n");
|
|
14507
|
+
}
|
|
14508
|
+
function assembleReport(result, productName, windowLabel) {
|
|
14509
|
+
const template = loadTemplate();
|
|
14510
|
+
const filled = template.replace("{{productName}}", productName).replace("{{windowLabel}}", windowLabel).replace("{{headlines}}", buildHeadlines(result)).replace("{{usage}}", buildUsage(result)).replace("{{systemPerformance}}", buildSystemPerformance(result)).replace("{{followups}}", buildFollowups(result));
|
|
14511
|
+
const swept = finalPiiSweep(filled);
|
|
14512
|
+
return truncateToFit(swept);
|
|
14513
|
+
}
|
|
14514
|
+
function extractHeadlines(report) {
|
|
14515
|
+
const lines = report.split("\n");
|
|
14516
|
+
const headlinesIdx = lines.findIndex((l) => l === "## Headlines" || l.startsWith("## Headlines"));
|
|
14517
|
+
if (headlinesIdx < 0) return lines.slice(0, 5).join("\n");
|
|
14518
|
+
let endIdx = lines.length;
|
|
14519
|
+
for (let i = headlinesIdx + 1; i < lines.length; i++) {
|
|
14520
|
+
const line = lines[i];
|
|
14521
|
+
if (line !== void 0 && line.startsWith("## ")) {
|
|
14522
|
+
endIdx = i;
|
|
14523
|
+
break;
|
|
14524
|
+
}
|
|
14525
|
+
}
|
|
14526
|
+
while (endIdx > headlinesIdx + 1 && lines[endIdx - 1] === "") endIdx--;
|
|
14527
|
+
return lines.slice(0, endIdx).join("\n");
|
|
14528
|
+
}
|
|
14529
|
+
function isoWeek(date) {
|
|
14530
|
+
const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
14531
|
+
const dayNum = d.getUTCDay() || 7;
|
|
14532
|
+
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
|
14533
|
+
const year = d.getUTCFullYear();
|
|
14534
|
+
const yearStart = new Date(Date.UTC(year, 0, 1));
|
|
14535
|
+
const week = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
|
|
14536
|
+
return { year, week };
|
|
14537
|
+
}
|
|
14538
|
+
function formatIsoWeek(w) {
|
|
14539
|
+
return `${w.year}-W${String(w.week).padStart(2, "0")}`;
|
|
14540
|
+
}
|
|
14541
|
+
function normalizeSince(since) {
|
|
14542
|
+
const m = /^(\d+)(h|d|w|mo)$/i.exec(since.trim());
|
|
14543
|
+
if (!m) {
|
|
14544
|
+
throw new Error(
|
|
14545
|
+
`Invalid lookback "${since}": expected format like "24h", "7d", "4w", or "3mo"`
|
|
14546
|
+
);
|
|
14547
|
+
}
|
|
14548
|
+
const n = m[1];
|
|
14549
|
+
const unit = m[2]?.toLowerCase();
|
|
14550
|
+
switch (unit) {
|
|
14551
|
+
case "h":
|
|
14552
|
+
return `${n} hours ago`;
|
|
14553
|
+
case "d":
|
|
14554
|
+
return `${n} days ago`;
|
|
14555
|
+
case "w":
|
|
14556
|
+
return `${n} weeks ago`;
|
|
14557
|
+
case "mo":
|
|
14558
|
+
return `${n} months ago`;
|
|
14559
|
+
default:
|
|
14560
|
+
throw new Error(`Invalid lookback "${since}"`);
|
|
14561
|
+
}
|
|
14562
|
+
}
|
|
14563
|
+
async function readCommits(opts) {
|
|
14564
|
+
let stdout;
|
|
14565
|
+
try {
|
|
14566
|
+
const r = await execFileAsync(
|
|
14567
|
+
"git",
|
|
14568
|
+
["log", `--since=${normalizeSince(opts.since)}`, "--name-only", "--format=%x1e%H%x1f%s"],
|
|
14569
|
+
{ cwd: opts.cwd, maxBuffer: 16 * 1024 * 1024 }
|
|
14570
|
+
);
|
|
14571
|
+
stdout = r.stdout;
|
|
14572
|
+
} catch (err) {
|
|
14573
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14574
|
+
if (EMPTY_REPO_RE.test(msg)) {
|
|
14575
|
+
process.stderr.write(`gitScan: empty repo or non-repo at ${opts.cwd}; returning []
|
|
14576
|
+
`);
|
|
14577
|
+
return [];
|
|
14578
|
+
}
|
|
14579
|
+
throw err;
|
|
14580
|
+
}
|
|
14581
|
+
const records = stdout.split("").filter((r) => r.trim().length > 0);
|
|
14582
|
+
return records.map((rec) => {
|
|
14583
|
+
const [header, ...fileLines] = rec.split("\n");
|
|
14584
|
+
const [sha, subject] = (header ?? "").split("");
|
|
14585
|
+
const files = fileLines.map((l) => l.trim()).filter((l) => l.length > 0);
|
|
14586
|
+
return { sha: sha ?? "", subject: subject ?? "", files };
|
|
14587
|
+
});
|
|
14588
|
+
}
|
|
14589
|
+
async function gitScan(opts) {
|
|
14590
|
+
const all = await readCommits(opts);
|
|
14591
|
+
const fixes = all.filter((c) => FIX_RE.test(c.subject));
|
|
14592
|
+
return fixes.map((c) => {
|
|
14593
|
+
const overlap = all.filter(
|
|
14594
|
+
(other) => other.sha !== c.sha && other.files.some((f) => c.files.includes(f))
|
|
14595
|
+
).length;
|
|
14596
|
+
return {
|
|
14597
|
+
sha: c.sha,
|
|
14598
|
+
subject: c.subject,
|
|
14599
|
+
filesChanged: c.files.length,
|
|
14600
|
+
branchIterations: overlap
|
|
14601
|
+
};
|
|
14602
|
+
});
|
|
14603
|
+
}
|
|
14604
|
+
async function computeHotspots(opts) {
|
|
14605
|
+
let stdout;
|
|
14606
|
+
try {
|
|
14607
|
+
const r = await execFileAsync2(
|
|
14608
|
+
"git",
|
|
14609
|
+
["log", `--since=${normalizeSince(opts.since)}`, "--name-only", "--format="],
|
|
14610
|
+
{ cwd: opts.cwd, maxBuffer: 16 * 1024 * 1024 }
|
|
14611
|
+
);
|
|
14612
|
+
stdout = r.stdout;
|
|
14613
|
+
} catch {
|
|
14614
|
+
return [];
|
|
14615
|
+
}
|
|
14616
|
+
const counts = /* @__PURE__ */ new Map();
|
|
14617
|
+
for (const line of stdout.split("\n")) {
|
|
14618
|
+
const path42 = line.trim();
|
|
14619
|
+
if (path42.length === 0) continue;
|
|
14620
|
+
counts.set(path42, (counts.get(path42) ?? 0) + 1);
|
|
14621
|
+
}
|
|
14622
|
+
return [...counts.entries()].filter(([, c]) => c > opts.threshold).map(([path42, churn]) => ({ path: path42, churn })).sort((a, b) => b.churn - a.churn);
|
|
14623
|
+
}
|
|
14624
|
+
function tokenize(text) {
|
|
14625
|
+
return new Set(
|
|
14626
|
+
text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((t) => t.length > 2 && !STOPWORDS.has(t))
|
|
14627
|
+
);
|
|
14628
|
+
}
|
|
14629
|
+
async function* walk22(dir) {
|
|
14630
|
+
let entries;
|
|
14631
|
+
try {
|
|
14632
|
+
entries = await fs43.readdir(dir, { withFileTypes: true });
|
|
14633
|
+
} catch {
|
|
14634
|
+
return;
|
|
14635
|
+
}
|
|
14636
|
+
for (const e of entries) {
|
|
14637
|
+
const p = path41.join(dir, e.name);
|
|
14638
|
+
if (e.isDirectory()) yield* walk22(p);
|
|
14639
|
+
else if (e.isFile() && e.name.endsWith(".md")) yield p;
|
|
14640
|
+
}
|
|
14641
|
+
}
|
|
14642
|
+
async function readDocumentedTokens(solutionsDir) {
|
|
14643
|
+
const docs = [];
|
|
14644
|
+
for (const [track, categories] of TRACK_CATEGORIES2) {
|
|
14645
|
+
for (const category of categories) {
|
|
14646
|
+
const dir = path41.join(solutionsDir, track, category);
|
|
14647
|
+
for await (const file of walk22(dir)) {
|
|
14648
|
+
const raw = await fs43.readFile(file, "utf-8");
|
|
14649
|
+
const m = /^#\s+(.+)$/m.exec(raw);
|
|
14650
|
+
const title = m?.[1] ?? path41.basename(file, ".md");
|
|
14651
|
+
docs.push(tokenize(title));
|
|
14652
|
+
}
|
|
14653
|
+
}
|
|
14654
|
+
}
|
|
14655
|
+
return docs;
|
|
14656
|
+
}
|
|
14657
|
+
function jaccard(a, b) {
|
|
14658
|
+
if (a.size === 0 || b.size === 0) return 0;
|
|
14659
|
+
let inter = 0;
|
|
14660
|
+
for (const t of a) if (b.has(t)) inter++;
|
|
14661
|
+
const union = a.size + b.size - inter;
|
|
14662
|
+
return union === 0 ? 0 : inter / union;
|
|
14663
|
+
}
|
|
14664
|
+
async function crossReferenceUndocumentedFixes(commits, solutionsDir) {
|
|
14665
|
+
const documented = await readDocumentedTokens(solutionsDir);
|
|
14666
|
+
const OVERLAP_THRESHOLD = 0.4;
|
|
14667
|
+
return commits.filter((c) => {
|
|
14668
|
+
const tokens = tokenize(c.subject);
|
|
14669
|
+
return !documented.some((d) => jaccard(tokens, d) >= OVERLAP_THRESHOLD);
|
|
14670
|
+
});
|
|
14671
|
+
}
|
|
14672
|
+
function suggestCategory(subject) {
|
|
14673
|
+
for (const [re, cat] of KEYWORD_TO_CATEGORY) if (re.test(subject)) return cat;
|
|
14674
|
+
return "bug-track/logic-errors";
|
|
14675
|
+
}
|
|
14676
|
+
function descriptor(subject) {
|
|
14677
|
+
return subject.replace(/^fix(\([^)]+\))?:\s*/i, "").trim();
|
|
14678
|
+
}
|
|
14679
|
+
function assembleCandidateReport(input) {
|
|
14680
|
+
const week = formatIsoWeek(input.isoWeek);
|
|
14681
|
+
const lines = [];
|
|
14682
|
+
lines.push(`# Compound candidates \u2014 week ${week}`, "");
|
|
14683
|
+
lines.push(`## Undocumented fixes (from \`git log\` past ${input.lookback})`, "");
|
|
14684
|
+
if (input.undocumentedFixes.length === 0) {
|
|
14685
|
+
lines.push("_(none this week)_", "");
|
|
14686
|
+
} else {
|
|
14687
|
+
for (const c of input.undocumentedFixes) {
|
|
14688
|
+
const d = descriptor(c.subject);
|
|
14689
|
+
const cat = suggestCategory(c.subject);
|
|
14690
|
+
lines.push(
|
|
14691
|
+
`- **${c.subject}** (commit ${c.sha.slice(0, 7)}, ${c.filesChanged} file(s), ${c.branchIterations} related commits)`
|
|
14692
|
+
);
|
|
14693
|
+
lines.push(` - Suggested category: ${cat}`);
|
|
14694
|
+
lines.push(` - Run: \`/harness:compound "${d}"\``);
|
|
14695
|
+
}
|
|
14696
|
+
lines.push("");
|
|
14697
|
+
}
|
|
14698
|
+
lines.push("## Pattern candidates (from churn + hotspot analysis)", "");
|
|
14699
|
+
if (input.hotspotCandidates.length === 0) {
|
|
14700
|
+
lines.push("_(none this week)_", "");
|
|
14701
|
+
} else {
|
|
14702
|
+
for (const h of input.hotspotCandidates) {
|
|
14703
|
+
lines.push(
|
|
14704
|
+
`- File \`${h.path}\` has ${h.churn} commits in ${input.lookback}; no docs/solutions/ entry`
|
|
14705
|
+
);
|
|
14706
|
+
lines.push(" - Suggested category: knowledge-track/architecture-patterns");
|
|
14707
|
+
lines.push(` - Run: \`/harness:compound "${h.path} pattern"\``);
|
|
14708
|
+
}
|
|
14709
|
+
lines.push("");
|
|
14710
|
+
}
|
|
14711
|
+
return lines.join("\n");
|
|
14712
|
+
}
|
|
14713
|
+
var VALID_TYPES, CONVENTIONAL_PATTERN, LOOKBACK_PATTERN, PulseDbSourceSchema, PulseSourcesSchema, PulseConfigSchema, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ALL_SOLUTION_CATEGORIES, ISO_DATE, BugTrackSchema, KnowledgeTrackSchema, BaseFrontmatter, SolutionDocFrontmatterSchema, TRACK_CATEGORIES, DEFAULT_AGNIX_TIMEOUT_MS, HARNESS_AGNIX_DISABLE, HARNESS_AGNIX_BIN, CLAUDE_MD_WARN_BYTES, CLAUDE_MD_ERROR_BYTES, CONTEXT_FILES, MIN_DESCRIPTION_LENGTH, SETTINGS_PATHS, KNOWN_HOOK_EVENTS, MCP_SETTINGS_FILES, REQUIRED_SECTIONS, SETTINGS_FILES, KNOWN_AGNIX_TOOLS, DEFAULT_SECTIONS, DEFAULT_RATIOS, NODE_TYPE_TO_CATEGORY, SECTION_LEVEL_MAP, DEFAULT_LEVEL, DEFAULT_BUDGET, DEFAULT_LOADER_CONFIG, LEVEL_FRACTIONS, PHASE_PRIORITIES, ManifestSchema, BundleConstraintsSchema, BundleSchema, ContributionsSchema, LockfilePackageSchema, LockfileSchema, SharableLayerSchema, SharableForbiddenImportSchema, SharableBoundaryConfigSchema, SharableSecurityRulesSchema, VALID_SCOPES, LINE_PATTERN, START_PATTERN, END_PATTERN, CODE_BLOCK_LANGUAGES, DEFAULT_DRIFT_CONFIG, FILE_TYPES, EXPORT_TYPES, CONVENTION_DESCRIPTIONS, RULE_CHECKERS, EntropyAnalyzer, readFile62, writeFile32, unlink22, mkdir22, copyFile2, DEFAULT_FIX_CONFIG, EXPORT_TYPE_KEYWORD, ALWAYS_UNSAFE_TYPES, idCounter, DEAD_CODE_FIX_ACTIONS, MustExportRuleSchema, MustExportDefaultRuleSchema, NoExportRuleSchema, MustImportRuleSchema, NoImportRuleSchema, NamingRuleSchema, MaxExportsRuleSchema, MaxLinesRuleSchema, RequireJSDocRuleSchema, RuleSchema, ConfigPatternSchema, PatternConfigSchema, DriftConfigSchema, DeadCodeConfigSchema, EntropyConfigSchema, BaselineManager, BenchmarkRunner, RegressionDetector, SKIP_DIRS, SOURCE_EXTENSIONS, FUNCTION_DECL_RE, CONST_DECL_RE, CriticalPathResolver, NoOpTelemetryAdapter, NoOpExecutor, ConsoleSink, feedbackConfig, ChecklistBuilder, AgentActionEmitter, globalEmitter, FileSink, NoOpSink, CategorySnapshotSchema, TimelineSnapshotSchema, TimelineFileSchema, TrendLineSchema, TrendResultSchema, DEFAULT_STABILITY_THRESHOLDS, ALL_CATEGORIES, TimelineManager, ConfidenceTierSchema, RegressionResultSchema, DirectionSchema, CategoryForecastSchema, SpecImpactSignalsSchema, SpecImpactEstimateSchema, ContributingFeatureSchema, AdjustedForecastSchema, PredictionWarningSchema, StabilityForecastSchema, PredictionResultSchema, PredictionOptionsSchema, VALID_STATUSES, EM_DASH, VALID_PRIORITIES, ALL_CATEGORIES2, DIRECTION_THRESHOLD, PredictionEngine, DEFAULT_COEFFICIENTS, SpecImpactEstimator, EMPTY_HISTORY, ViolationHistoryManager, NORMALIZERS, MAX_SAMPLES, DEFAULT_WINDOW_WEEKS, DEFAULT_MIN_OCCURRENCES, FailureEntrySchema, HandoffSchema, GateCheckSchema, GateResultSchema, GateConfigSchema, HarnessStateSchema, DEFAULT_STATE, StreamInfoSchema, StreamIndexSchema, DEFAULT_STREAM_INDEX, HARNESS_DIR, STATE_FILE, LEARNINGS_FILE, FAILURES_FILE, HANDOFF_FILE, GATE_CONFIG_FILE, INDEX_FILE, SESSIONS_DIR, SESSION_INDEX_FILE, SUMMARY_FILE, SESSION_STATE_FILE, ARCHIVE_DIR, CONTENT_HASHES_FILE, EVENTS_FILE, STREAMS_DIR, STREAM_NAME_REGEX, branchCache, BRANCH_CACHE_TTL_MS, STATE_FILES, MAX_CACHE_ENTRIES, learningsCacheMap, WEIGHTS, LOCK_RETRIES, LOCK_BACKOFFS, PROMOTABLE_OUTCOMES, failuresCacheMap, FAILURE_LINE_REGEX, SAFE_GATE_COMMAND, SkillEventSchema, knownHashesCache, EVENT_FORMATTERS, RuleRegistry, DEFAULT_SECURITY_CONFIG, RuleOverrideSchema, SecurityConfigSchema, secretRules, injectionRules, xssRules, cryptoRules, pathTraversalRules, networkRules, deserializationRules, agentConfigRules, mcpRules, insecureDefaultsRules, sharpEdgesRules, nodeRules, expressRules, reactRules, goRules, SecurityScanner, hiddenUnicodePatterns, reRolingPatterns, permissionEscalationPatterns, encodedPayloadPatterns, indirectInjectionPatterns, contextManipulationPatterns, socialEngineeringPatterns, suspiciousPatterns, ALL_PATTERNS, DESTRUCTIVE_BASH, TAINT_DURATION_MS, DEFAULT_SESSION_ID, SecurityCategorySnapshotSchema, SupplyChainSnapshotSchema, SecurityTimelineSnapshotSchema, FindingLifecycleSchema, SecurityTimelineFileSchema, DirectionSchema2, SecurityTrendLineSchema, TrendAttributionSchema, SecurityTrendResultSchema, TimeToFixStatsSchema, TimeToFixResultSchema, EMPTY_SUPPLY_CHAIN, SecurityTimelineManager, ALL_CHECKS, STATUS_ICONS, CINotifier, ExclusionSet, PREFIX_PATTERNS, TEST_FILE_PATTERN, MD_FILE_PATTERN, ALL_DOMAINS, SECURITY_PATTERNS, SEVERITY_RANK, SEVERITY_ORDER, SEVERITY_LABELS, VALIDATED_BY_RANK, VALIDATION_SCORES, DOMAIN_BASELINES, FACTOR_WEIGHTS, EVIDENCE_SATURATION, CORROBORATED_AGREEMENT, STANDALONE_AGREEMENT, AGREEMENT_LINE_GAP, COMPLIANCE_DESCRIPTOR, EXPORT_RE, BUG_DETECTION_DESCRIPTOR, SECURITY_DESCRIPTOR, EVAL_PATTERN, SECRET_PATTERNS, SQL_CONCAT_PATTERN, SHELL_EXEC_PATTERN, ARCHITECTURE_DESCRIPTOR, LARGE_FILE_THRESHOLD, VIOLATION_FILE_RE, LEARNINGS_DESCRIPTOR, RELEVANCE_THRESHOLD, AGENT_DESCRIPTORS, AGENT_RUNNERS, DOWNGRADE_MAP, DEFAULT_PROVIDER_TIERS, SMALL_SUGGESTION_LINE_LIMIT, FILE_LINE_RANGE_PATTERN, FILE_LINE_PATTERN, FILE_ONLY_PATTERN, SECURITY_SENSITIVE_PATH, MIGRATION_PATH, TEST_PATH, CONFIG_PATH, STAGE_DOMAINS, EM_DASH2, STATUS_RANK, RETRY_DEFAULTS, GitHubIssuesSyncAdapter, syncMutex, PRIORITY_RANK, POSITION_WEIGHT, DEPENDENTS_WEIGHT, AFFINITY_WEIGHT, InteractionTypeSchema, QuestionSchema, ConfirmationSchema, TransitionSchema, EmitInteractionInputSchema, ProjectScanner, SHELL_TEMPLATE, STYLES, SCRIPTS, MockLLMService, llmService, ContentPipeline, BlueprintGenerator, TOKENS_PER_MILLION, fallback_default, LITELLM_PRICING_URL, CACHE_TTL_MS, STALENESS_WARNING_DAYS, MICRODOLLARS_PER_DOLLAR, TOKENS_PER_MILLION2, StructuralStrategy, DEFAULT_TOKEN_BUDGET, CHARS_PER_TOKEN, TRUNCATION_MARKER, TruncationStrategy, CompactionPipeline, STABILITY_LOOKUP, TIER_ORDER, AnthropicCacheAdapter, TIER_ORDER2, OpenAICacheAdapter, TIER_ORDER3, CACHED_CONTENT_MARKER, GeminiCacheAdapter, VERSION, POSTHOG_BATCH_URL, MAX_ATTEMPTS, TIMEOUT_MS, CompoundLockHeldError, KNOWN_CATEGORIES, ALLOWED_FIELD_KEYS, PII_TOKENS, PII_FIELD_DENYLIST, PII_LINE_RE, ALLOWED_SET, PulseAdapterAlreadyRegisteredError, REGISTRY, MOCK_ADAPTER_NAME, ALLOWED_FIELD_SET, adapter, LOOKBACK_RE, MAX_LINES, INLINE_TEMPLATE, TRUNCATION_MARKER2, execFileAsync, FIX_RE, EMPTY_REPO_RE, execFileAsync2, TRACK_CATEGORIES2, STOPWORDS, KEYWORD_TO_CATEGORY;
|
|
14029
14714
|
var init_dist3 = __esm({
|
|
14030
14715
|
"../core/dist/index.mjs"() {
|
|
14031
14716
|
init_chunk_H73442AZ();
|
|
@@ -14050,6 +14735,76 @@ var init_dist3 = __esm({
|
|
|
14050
14735
|
"revert"
|
|
14051
14736
|
];
|
|
14052
14737
|
CONVENTIONAL_PATTERN = /^(\w+)(\(([^)]+)\))?(!)?: (.+)$/;
|
|
14738
|
+
LOOKBACK_PATTERN = /^\d+(h|d|w)$/;
|
|
14739
|
+
PulseDbSourceSchema = z2.object({
|
|
14740
|
+
enabled: z2.boolean(),
|
|
14741
|
+
connectionEnv: z2.string().optional()
|
|
14742
|
+
});
|
|
14743
|
+
PulseSourcesSchema = z2.object({
|
|
14744
|
+
analytics: z2.string().nullable(),
|
|
14745
|
+
tracing: z2.string().nullable(),
|
|
14746
|
+
payments: z2.string().nullable(),
|
|
14747
|
+
db: PulseDbSourceSchema
|
|
14748
|
+
});
|
|
14749
|
+
PulseConfigSchema = z2.object({
|
|
14750
|
+
enabled: z2.boolean(),
|
|
14751
|
+
lookbackDefault: z2.string().regex(LOOKBACK_PATTERN, 'lookback must be like "24h", "7d", or "1w"'),
|
|
14752
|
+
primaryEvent: z2.string(),
|
|
14753
|
+
valueEvent: z2.string(),
|
|
14754
|
+
completionEvents: z2.array(z2.string()),
|
|
14755
|
+
qualityScoring: z2.boolean(),
|
|
14756
|
+
qualityDimension: z2.string().nullable(),
|
|
14757
|
+
sources: PulseSourcesSchema,
|
|
14758
|
+
metricSourceOverrides: z2.record(z2.string(), z2.string()),
|
|
14759
|
+
pendingMetrics: z2.array(z2.string()),
|
|
14760
|
+
excludedMetrics: z2.array(z2.string())
|
|
14761
|
+
});
|
|
14762
|
+
BUG_TRACK_CATEGORIES = [
|
|
14763
|
+
"build-errors",
|
|
14764
|
+
"test-failures",
|
|
14765
|
+
"runtime-errors",
|
|
14766
|
+
"performance-issues",
|
|
14767
|
+
"database-issues",
|
|
14768
|
+
"security-issues",
|
|
14769
|
+
"ui-bugs",
|
|
14770
|
+
"integration-issues",
|
|
14771
|
+
"logic-errors"
|
|
14772
|
+
];
|
|
14773
|
+
KNOWLEDGE_TRACK_CATEGORIES = [
|
|
14774
|
+
"architecture-patterns",
|
|
14775
|
+
"design-patterns",
|
|
14776
|
+
"tooling-decisions",
|
|
14777
|
+
"conventions",
|
|
14778
|
+
"dx",
|
|
14779
|
+
"best-practices"
|
|
14780
|
+
];
|
|
14781
|
+
ALL_SOLUTION_CATEGORIES = [
|
|
14782
|
+
...BUG_TRACK_CATEGORIES,
|
|
14783
|
+
...KNOWLEDGE_TRACK_CATEGORIES
|
|
14784
|
+
];
|
|
14785
|
+
ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
14786
|
+
BugTrackSchema = z22.object({
|
|
14787
|
+
track: z22.literal("bug-track"),
|
|
14788
|
+
category: z22.enum(BUG_TRACK_CATEGORIES)
|
|
14789
|
+
});
|
|
14790
|
+
KnowledgeTrackSchema = z22.object({
|
|
14791
|
+
track: z22.literal("knowledge-track"),
|
|
14792
|
+
category: z22.enum(KNOWLEDGE_TRACK_CATEGORIES)
|
|
14793
|
+
});
|
|
14794
|
+
BaseFrontmatter = z22.object({
|
|
14795
|
+
module: z22.string().min(1),
|
|
14796
|
+
tags: z22.array(z22.string()),
|
|
14797
|
+
problem_type: z22.string().min(1),
|
|
14798
|
+
last_updated: z22.string().regex(ISO_DATE, "last_updated must be ISO date YYYY-MM-DD")
|
|
14799
|
+
});
|
|
14800
|
+
SolutionDocFrontmatterSchema = z22.discriminatedUnion("track", [
|
|
14801
|
+
BaseFrontmatter.merge(BugTrackSchema),
|
|
14802
|
+
BaseFrontmatter.merge(KnowledgeTrackSchema)
|
|
14803
|
+
]);
|
|
14804
|
+
TRACK_CATEGORIES = [
|
|
14805
|
+
["bug-track", BUG_TRACK_CATEGORIES],
|
|
14806
|
+
["knowledge-track", KNOWLEDGE_TRACK_CATEGORIES]
|
|
14807
|
+
];
|
|
14053
14808
|
DEFAULT_AGNIX_TIMEOUT_MS = 3e4;
|
|
14054
14809
|
HARNESS_AGNIX_DISABLE = "HARNESS_AGNIX_DISABLE";
|
|
14055
14810
|
HARNESS_AGNIX_BIN = "HARNESS_AGNIX_BIN";
|
|
@@ -14196,81 +14951,81 @@ var init_dist3 = __esm({
|
|
|
14196
14951
|
{ category: "config", patterns: ["harness.config.json", "package.json"], priority: 5 }
|
|
14197
14952
|
]
|
|
14198
14953
|
};
|
|
14199
|
-
ManifestSchema =
|
|
14200
|
-
name:
|
|
14201
|
-
version:
|
|
14202
|
-
description:
|
|
14203
|
-
include:
|
|
14204
|
-
minHarnessVersion:
|
|
14205
|
-
keywords:
|
|
14206
|
-
layers:
|
|
14207
|
-
boundaries:
|
|
14208
|
-
|
|
14209
|
-
name:
|
|
14210
|
-
layer:
|
|
14211
|
-
direction:
|
|
14212
|
-
schema:
|
|
14954
|
+
ManifestSchema = z3.object({
|
|
14955
|
+
name: z3.string(),
|
|
14956
|
+
version: z3.string(),
|
|
14957
|
+
description: z3.string().optional(),
|
|
14958
|
+
include: z3.array(z3.string()).min(1),
|
|
14959
|
+
minHarnessVersion: z3.string().optional(),
|
|
14960
|
+
keywords: z3.array(z3.string()).optional().default([]),
|
|
14961
|
+
layers: z3.record(z3.array(z3.string())).optional(),
|
|
14962
|
+
boundaries: z3.array(
|
|
14963
|
+
z3.object({
|
|
14964
|
+
name: z3.string(),
|
|
14965
|
+
layer: z3.string(),
|
|
14966
|
+
direction: z3.enum(["input", "output"]),
|
|
14967
|
+
schema: z3.string()
|
|
14213
14968
|
})
|
|
14214
14969
|
).optional()
|
|
14215
14970
|
});
|
|
14216
|
-
BundleConstraintsSchema =
|
|
14217
|
-
layers:
|
|
14218
|
-
|
|
14219
|
-
name:
|
|
14220
|
-
pattern:
|
|
14221
|
-
allowedDependencies:
|
|
14971
|
+
BundleConstraintsSchema = z3.object({
|
|
14972
|
+
layers: z3.array(
|
|
14973
|
+
z3.object({
|
|
14974
|
+
name: z3.string(),
|
|
14975
|
+
pattern: z3.string(),
|
|
14976
|
+
allowedDependencies: z3.array(z3.string())
|
|
14222
14977
|
})
|
|
14223
14978
|
).optional(),
|
|
14224
|
-
forbiddenImports:
|
|
14225
|
-
|
|
14226
|
-
from:
|
|
14227
|
-
disallow:
|
|
14228
|
-
message:
|
|
14979
|
+
forbiddenImports: z3.array(
|
|
14980
|
+
z3.object({
|
|
14981
|
+
from: z3.string(),
|
|
14982
|
+
disallow: z3.array(z3.string()),
|
|
14983
|
+
message: z3.string().optional()
|
|
14229
14984
|
})
|
|
14230
14985
|
).optional(),
|
|
14231
|
-
boundaries:
|
|
14232
|
-
requireSchema:
|
|
14986
|
+
boundaries: z3.object({
|
|
14987
|
+
requireSchema: z3.array(z3.string()).optional()
|
|
14233
14988
|
}).optional(),
|
|
14234
|
-
architecture:
|
|
14235
|
-
thresholds:
|
|
14236
|
-
modules:
|
|
14989
|
+
architecture: z3.object({
|
|
14990
|
+
thresholds: z3.record(z3.unknown()).optional(),
|
|
14991
|
+
modules: z3.record(z3.record(z3.unknown())).optional()
|
|
14237
14992
|
}).optional(),
|
|
14238
|
-
security:
|
|
14239
|
-
rules:
|
|
14993
|
+
security: z3.object({
|
|
14994
|
+
rules: z3.record(z3.string()).optional()
|
|
14240
14995
|
}).optional()
|
|
14241
14996
|
});
|
|
14242
|
-
BundleSchema =
|
|
14243
|
-
name:
|
|
14244
|
-
version:
|
|
14245
|
-
description:
|
|
14246
|
-
minHarnessVersion:
|
|
14997
|
+
BundleSchema = z3.object({
|
|
14998
|
+
name: z3.string(),
|
|
14999
|
+
version: z3.string(),
|
|
15000
|
+
description: z3.string().optional(),
|
|
15001
|
+
minHarnessVersion: z3.string().optional(),
|
|
14247
15002
|
manifest: ManifestSchema,
|
|
14248
15003
|
constraints: BundleConstraintsSchema,
|
|
14249
|
-
contributions:
|
|
15004
|
+
contributions: z3.record(z3.unknown()).optional()
|
|
14250
15005
|
});
|
|
14251
|
-
ContributionsSchema =
|
|
14252
|
-
LockfilePackageSchema =
|
|
14253
|
-
version:
|
|
14254
|
-
source:
|
|
14255
|
-
installedAt:
|
|
14256
|
-
contributions:
|
|
14257
|
-
resolved:
|
|
14258
|
-
integrity:
|
|
14259
|
-
provenance:
|
|
15006
|
+
ContributionsSchema = z3.record(z3.unknown());
|
|
15007
|
+
LockfilePackageSchema = z3.object({
|
|
15008
|
+
version: z3.string(),
|
|
15009
|
+
source: z3.string(),
|
|
15010
|
+
installedAt: z3.string(),
|
|
15011
|
+
contributions: z3.record(z3.unknown()).optional().nullable(),
|
|
15012
|
+
resolved: z3.string().optional(),
|
|
15013
|
+
integrity: z3.string().optional(),
|
|
15014
|
+
provenance: z3.array(z3.string()).optional()
|
|
14260
15015
|
});
|
|
14261
|
-
LockfileSchema =
|
|
14262
|
-
version:
|
|
15016
|
+
LockfileSchema = z3.object({
|
|
15017
|
+
version: z3.literal(1).optional(),
|
|
14263
15018
|
// Used by some tests
|
|
14264
|
-
lockfileVersion:
|
|
15019
|
+
lockfileVersion: z3.literal(1).optional(),
|
|
14265
15020
|
// Standard field
|
|
14266
|
-
packages:
|
|
15021
|
+
packages: z3.record(LockfilePackageSchema)
|
|
14267
15022
|
}).refine((data) => data.version !== void 0 || data.lockfileVersion !== void 0, {
|
|
14268
15023
|
message: "Either 'version' or 'lockfileVersion' must be present and equal to 1"
|
|
14269
15024
|
});
|
|
14270
|
-
SharableLayerSchema =
|
|
14271
|
-
SharableForbiddenImportSchema =
|
|
14272
|
-
SharableBoundaryConfigSchema =
|
|
14273
|
-
SharableSecurityRulesSchema =
|
|
15025
|
+
SharableLayerSchema = z3.unknown();
|
|
15026
|
+
SharableForbiddenImportSchema = z3.unknown();
|
|
15027
|
+
SharableBoundaryConfigSchema = z3.unknown();
|
|
15028
|
+
SharableSecurityRulesSchema = z3.unknown();
|
|
14274
15029
|
VALID_SCOPES = /* @__PURE__ */ new Set([
|
|
14275
15030
|
"entropy",
|
|
14276
15031
|
"architecture",
|
|
@@ -14541,11 +15296,11 @@ var init_dist3 = __esm({
|
|
|
14541
15296
|
return detectPatternViolations(snapshotResult.value, config);
|
|
14542
15297
|
}
|
|
14543
15298
|
};
|
|
14544
|
-
|
|
14545
|
-
writeFile32 = promisify2(
|
|
14546
|
-
unlink22 = promisify2(
|
|
14547
|
-
mkdir22 = promisify2(
|
|
14548
|
-
copyFile2 = promisify2(
|
|
15299
|
+
readFile62 = promisify2(fs5.readFile);
|
|
15300
|
+
writeFile32 = promisify2(fs5.writeFile);
|
|
15301
|
+
unlink22 = promisify2(fs5.unlink);
|
|
15302
|
+
mkdir22 = promisify2(fs5.mkdir);
|
|
15303
|
+
copyFile2 = promisify2(fs5.copyFile);
|
|
14549
15304
|
DEFAULT_FIX_CONFIG = {
|
|
14550
15305
|
dryRun: false,
|
|
14551
15306
|
fixTypes: ["unused-imports", "dead-files"],
|
|
@@ -14573,45 +15328,45 @@ var init_dist3 = __esm({
|
|
|
14573
15328
|
"commented-code": "Delete commented block",
|
|
14574
15329
|
"unused-import": "Remove import"
|
|
14575
15330
|
};
|
|
14576
|
-
MustExportRuleSchema =
|
|
14577
|
-
type:
|
|
14578
|
-
names:
|
|
15331
|
+
MustExportRuleSchema = z4.object({
|
|
15332
|
+
type: z4.literal("must-export"),
|
|
15333
|
+
names: z4.array(z4.string())
|
|
14579
15334
|
});
|
|
14580
|
-
MustExportDefaultRuleSchema =
|
|
14581
|
-
type:
|
|
14582
|
-
kind:
|
|
15335
|
+
MustExportDefaultRuleSchema = z4.object({
|
|
15336
|
+
type: z4.literal("must-export-default"),
|
|
15337
|
+
kind: z4.enum(["class", "function", "object"]).optional()
|
|
14583
15338
|
});
|
|
14584
|
-
NoExportRuleSchema =
|
|
14585
|
-
type:
|
|
14586
|
-
names:
|
|
15339
|
+
NoExportRuleSchema = z4.object({
|
|
15340
|
+
type: z4.literal("no-export"),
|
|
15341
|
+
names: z4.array(z4.string())
|
|
14587
15342
|
});
|
|
14588
|
-
MustImportRuleSchema =
|
|
14589
|
-
type:
|
|
14590
|
-
from:
|
|
14591
|
-
names:
|
|
15343
|
+
MustImportRuleSchema = z4.object({
|
|
15344
|
+
type: z4.literal("must-import"),
|
|
15345
|
+
from: z4.string(),
|
|
15346
|
+
names: z4.array(z4.string()).optional()
|
|
14592
15347
|
});
|
|
14593
|
-
NoImportRuleSchema =
|
|
14594
|
-
type:
|
|
14595
|
-
from:
|
|
15348
|
+
NoImportRuleSchema = z4.object({
|
|
15349
|
+
type: z4.literal("no-import"),
|
|
15350
|
+
from: z4.string()
|
|
14596
15351
|
});
|
|
14597
|
-
NamingRuleSchema =
|
|
14598
|
-
type:
|
|
14599
|
-
match:
|
|
14600
|
-
convention:
|
|
15352
|
+
NamingRuleSchema = z4.object({
|
|
15353
|
+
type: z4.literal("naming"),
|
|
15354
|
+
match: z4.string(),
|
|
15355
|
+
convention: z4.enum(["camelCase", "PascalCase", "UPPER_SNAKE", "kebab-case"])
|
|
14601
15356
|
});
|
|
14602
|
-
MaxExportsRuleSchema =
|
|
14603
|
-
type:
|
|
14604
|
-
count:
|
|
15357
|
+
MaxExportsRuleSchema = z4.object({
|
|
15358
|
+
type: z4.literal("max-exports"),
|
|
15359
|
+
count: z4.number().positive()
|
|
14605
15360
|
});
|
|
14606
|
-
MaxLinesRuleSchema =
|
|
14607
|
-
type:
|
|
14608
|
-
count:
|
|
15361
|
+
MaxLinesRuleSchema = z4.object({
|
|
15362
|
+
type: z4.literal("max-lines"),
|
|
15363
|
+
count: z4.number().positive()
|
|
14609
15364
|
});
|
|
14610
|
-
RequireJSDocRuleSchema =
|
|
14611
|
-
type:
|
|
14612
|
-
for:
|
|
15365
|
+
RequireJSDocRuleSchema = z4.object({
|
|
15366
|
+
type: z4.literal("require-jsdoc"),
|
|
15367
|
+
for: z4.array(z4.enum(["function", "class", "export"]))
|
|
14613
15368
|
});
|
|
14614
|
-
RuleSchema =
|
|
15369
|
+
RuleSchema = z4.discriminatedUnion("type", [
|
|
14615
15370
|
MustExportRuleSchema,
|
|
14616
15371
|
MustExportDefaultRuleSchema,
|
|
14617
15372
|
NoExportRuleSchema,
|
|
@@ -14622,52 +15377,52 @@ var init_dist3 = __esm({
|
|
|
14622
15377
|
MaxLinesRuleSchema,
|
|
14623
15378
|
RequireJSDocRuleSchema
|
|
14624
15379
|
]);
|
|
14625
|
-
ConfigPatternSchema =
|
|
14626
|
-
name:
|
|
14627
|
-
description:
|
|
14628
|
-
severity:
|
|
14629
|
-
files:
|
|
15380
|
+
ConfigPatternSchema = z4.object({
|
|
15381
|
+
name: z4.string().min(1),
|
|
15382
|
+
description: z4.string(),
|
|
15383
|
+
severity: z4.enum(["error", "warning"]),
|
|
15384
|
+
files: z4.array(z4.string()),
|
|
14630
15385
|
rule: RuleSchema,
|
|
14631
|
-
message:
|
|
15386
|
+
message: z4.string().optional()
|
|
14632
15387
|
});
|
|
14633
|
-
PatternConfigSchema =
|
|
14634
|
-
patterns:
|
|
14635
|
-
customPatterns:
|
|
15388
|
+
PatternConfigSchema = z4.object({
|
|
15389
|
+
patterns: z4.array(ConfigPatternSchema),
|
|
15390
|
+
customPatterns: z4.array(z4.any()).optional(),
|
|
14636
15391
|
// Code patterns are functions, can't validate
|
|
14637
|
-
ignoreFiles:
|
|
15392
|
+
ignoreFiles: z4.array(z4.string()).optional()
|
|
14638
15393
|
});
|
|
14639
|
-
DriftConfigSchema =
|
|
14640
|
-
docPaths:
|
|
14641
|
-
checkApiSignatures:
|
|
14642
|
-
checkExamples:
|
|
14643
|
-
checkStructure:
|
|
14644
|
-
ignorePatterns:
|
|
15394
|
+
DriftConfigSchema = z4.object({
|
|
15395
|
+
docPaths: z4.array(z4.string()).optional(),
|
|
15396
|
+
checkApiSignatures: z4.boolean().optional(),
|
|
15397
|
+
checkExamples: z4.boolean().optional(),
|
|
15398
|
+
checkStructure: z4.boolean().optional(),
|
|
15399
|
+
ignorePatterns: z4.array(z4.string()).optional()
|
|
14645
15400
|
});
|
|
14646
|
-
DeadCodeConfigSchema =
|
|
14647
|
-
entryPoints:
|
|
14648
|
-
includeTypes:
|
|
14649
|
-
includeInternals:
|
|
14650
|
-
ignorePatterns:
|
|
14651
|
-
treatDynamicImportsAs:
|
|
15401
|
+
DeadCodeConfigSchema = z4.object({
|
|
15402
|
+
entryPoints: z4.array(z4.string()).optional(),
|
|
15403
|
+
includeTypes: z4.boolean().optional(),
|
|
15404
|
+
includeInternals: z4.boolean().optional(),
|
|
15405
|
+
ignorePatterns: z4.array(z4.string()).optional(),
|
|
15406
|
+
treatDynamicImportsAs: z4.enum(["used", "unknown"]).optional()
|
|
14652
15407
|
});
|
|
14653
|
-
EntropyConfigSchema =
|
|
14654
|
-
rootDir:
|
|
14655
|
-
parser:
|
|
15408
|
+
EntropyConfigSchema = z4.object({
|
|
15409
|
+
rootDir: z4.string(),
|
|
15410
|
+
parser: z4.any().optional(),
|
|
14656
15411
|
// LanguageParser instance, can't validate
|
|
14657
|
-
entryPoints:
|
|
14658
|
-
analyze:
|
|
14659
|
-
drift:
|
|
14660
|
-
deadCode:
|
|
14661
|
-
patterns:
|
|
15412
|
+
entryPoints: z4.array(z4.string()).optional(),
|
|
15413
|
+
analyze: z4.object({
|
|
15414
|
+
drift: z4.union([z4.boolean(), DriftConfigSchema]).optional(),
|
|
15415
|
+
deadCode: z4.union([z4.boolean(), DeadCodeConfigSchema]).optional(),
|
|
15416
|
+
patterns: z4.union([z4.boolean(), PatternConfigSchema]).optional()
|
|
14662
15417
|
}),
|
|
14663
|
-
include:
|
|
14664
|
-
exclude:
|
|
14665
|
-
docPaths:
|
|
15418
|
+
include: z4.array(z4.string()).optional(),
|
|
15419
|
+
exclude: z4.array(z4.string()).optional(),
|
|
15420
|
+
docPaths: z4.array(z4.string()).optional()
|
|
14666
15421
|
});
|
|
14667
15422
|
BaselineManager = class {
|
|
14668
15423
|
baselinesPath;
|
|
14669
15424
|
constructor(projectRoot) {
|
|
14670
|
-
this.baselinesPath =
|
|
15425
|
+
this.baselinesPath = join17(projectRoot, ".harness", "perf", "baselines.json");
|
|
14671
15426
|
}
|
|
14672
15427
|
/**
|
|
14673
15428
|
* Load the baselines file from disk.
|
|
@@ -14942,16 +15697,16 @@ var init_dist3 = __esm({
|
|
|
14942
15697
|
walkDir(dir, entries) {
|
|
14943
15698
|
let items;
|
|
14944
15699
|
try {
|
|
14945
|
-
items =
|
|
15700
|
+
items = fs6.readdirSync(dir, { withFileTypes: true });
|
|
14946
15701
|
} catch {
|
|
14947
15702
|
return;
|
|
14948
15703
|
}
|
|
14949
15704
|
for (const item of items) {
|
|
14950
15705
|
if (item.isDirectory()) {
|
|
14951
15706
|
if (SKIP_DIRS.has(item.name)) continue;
|
|
14952
|
-
this.walkDir(
|
|
14953
|
-
} else if (item.isFile() && SOURCE_EXTENSIONS.has(
|
|
14954
|
-
this.scanFile(
|
|
15707
|
+
this.walkDir(path3.join(dir, item.name), entries);
|
|
15708
|
+
} else if (item.isFile() && SOURCE_EXTENSIONS.has(path3.extname(item.name))) {
|
|
15709
|
+
this.scanFile(path3.join(dir, item.name), entries);
|
|
14955
15710
|
}
|
|
14956
15711
|
}
|
|
14957
15712
|
}
|
|
@@ -14966,12 +15721,12 @@ var init_dist3 = __esm({
|
|
|
14966
15721
|
scanFile(filePath, entries) {
|
|
14967
15722
|
let content;
|
|
14968
15723
|
try {
|
|
14969
|
-
content =
|
|
15724
|
+
content = fs6.readFileSync(filePath, "utf-8");
|
|
14970
15725
|
} catch {
|
|
14971
15726
|
return;
|
|
14972
15727
|
}
|
|
14973
15728
|
const lines = content.split("\n");
|
|
14974
|
-
const relativePath =
|
|
15729
|
+
const relativePath = path3.relative(this.projectRoot, filePath).replace(/\\/g, "/");
|
|
14975
15730
|
for (let i = 0; i < lines.length; i++) {
|
|
14976
15731
|
if (!lines[i].includes("@perf-critical")) continue;
|
|
14977
15732
|
const fnName = this.resolveFunctionName(lines, i + 1);
|
|
@@ -15370,46 +16125,46 @@ var init_dist3 = __esm({
|
|
|
15370
16125
|
return Ok(void 0);
|
|
15371
16126
|
}
|
|
15372
16127
|
};
|
|
15373
|
-
CategorySnapshotSchema =
|
|
16128
|
+
CategorySnapshotSchema = z5.object({
|
|
15374
16129
|
/** Aggregate metric value (e.g., violation count, avg complexity) */
|
|
15375
|
-
value:
|
|
16130
|
+
value: z5.number(),
|
|
15376
16131
|
/** Count of violations in this category */
|
|
15377
|
-
violationCount:
|
|
16132
|
+
violationCount: z5.number()
|
|
15378
16133
|
});
|
|
15379
|
-
TimelineSnapshotSchema =
|
|
16134
|
+
TimelineSnapshotSchema = z5.object({
|
|
15380
16135
|
/** ISO 8601 timestamp of capture */
|
|
15381
|
-
capturedAt:
|
|
16136
|
+
capturedAt: z5.string().datetime(),
|
|
15382
16137
|
/** Git commit hash at capture time */
|
|
15383
|
-
commitHash:
|
|
16138
|
+
commitHash: z5.string(),
|
|
15384
16139
|
/** Composite stability score (0-100, higher is healthier) */
|
|
15385
|
-
stabilityScore:
|
|
16140
|
+
stabilityScore: z5.number().min(0).max(100),
|
|
15386
16141
|
/** Per-category metric aggregates */
|
|
15387
|
-
metrics:
|
|
16142
|
+
metrics: z5.record(ArchMetricCategorySchema, CategorySnapshotSchema)
|
|
15388
16143
|
});
|
|
15389
|
-
TimelineFileSchema =
|
|
15390
|
-
version:
|
|
15391
|
-
snapshots:
|
|
16144
|
+
TimelineFileSchema = z5.object({
|
|
16145
|
+
version: z5.literal(1),
|
|
16146
|
+
snapshots: z5.array(TimelineSnapshotSchema)
|
|
15392
16147
|
});
|
|
15393
|
-
TrendLineSchema =
|
|
16148
|
+
TrendLineSchema = z5.object({
|
|
15394
16149
|
/** Current value */
|
|
15395
|
-
current:
|
|
16150
|
+
current: z5.number(),
|
|
15396
16151
|
/** Previous value (from comparison snapshot) */
|
|
15397
|
-
previous:
|
|
16152
|
+
previous: z5.number(),
|
|
15398
16153
|
/** Absolute delta (current - previous) */
|
|
15399
|
-
delta:
|
|
16154
|
+
delta: z5.number(),
|
|
15400
16155
|
/** Direction indicator */
|
|
15401
|
-
direction:
|
|
16156
|
+
direction: z5.enum(["improving", "stable", "declining"])
|
|
15402
16157
|
});
|
|
15403
|
-
TrendResultSchema =
|
|
16158
|
+
TrendResultSchema = z5.object({
|
|
15404
16159
|
/** Overall stability trend */
|
|
15405
16160
|
stability: TrendLineSchema,
|
|
15406
16161
|
/** Per-category trends */
|
|
15407
|
-
categories:
|
|
16162
|
+
categories: z5.record(ArchMetricCategorySchema, TrendLineSchema),
|
|
15408
16163
|
/** Number of snapshots analyzed */
|
|
15409
|
-
snapshotCount:
|
|
16164
|
+
snapshotCount: z5.number(),
|
|
15410
16165
|
/** Time range covered */
|
|
15411
|
-
from:
|
|
15412
|
-
to:
|
|
16166
|
+
from: z5.string(),
|
|
16167
|
+
to: z5.string()
|
|
15413
16168
|
});
|
|
15414
16169
|
DEFAULT_STABILITY_THRESHOLDS = {
|
|
15415
16170
|
"circular-deps": 5,
|
|
@@ -15424,7 +16179,7 @@ var init_dist3 = __esm({
|
|
|
15424
16179
|
TimelineManager = class {
|
|
15425
16180
|
timelinePath;
|
|
15426
16181
|
constructor(rootDir) {
|
|
15427
|
-
this.timelinePath =
|
|
16182
|
+
this.timelinePath = join19(rootDir, ".harness", "arch", "timeline.json");
|
|
15428
16183
|
}
|
|
15429
16184
|
/**
|
|
15430
16185
|
* Load timeline from disk.
|
|
@@ -15608,80 +16363,80 @@ var init_dist3 = __esm({
|
|
|
15608
16363
|
};
|
|
15609
16364
|
}
|
|
15610
16365
|
};
|
|
15611
|
-
ConfidenceTierSchema =
|
|
15612
|
-
RegressionResultSchema =
|
|
15613
|
-
slope:
|
|
15614
|
-
intercept:
|
|
15615
|
-
rSquared:
|
|
15616
|
-
dataPoints:
|
|
16366
|
+
ConfidenceTierSchema = z6.enum(["high", "medium", "low"]);
|
|
16367
|
+
RegressionResultSchema = z6.object({
|
|
16368
|
+
slope: z6.number(),
|
|
16369
|
+
intercept: z6.number(),
|
|
16370
|
+
rSquared: z6.number().min(0).max(1),
|
|
16371
|
+
dataPoints: z6.number().int().min(0)
|
|
15617
16372
|
});
|
|
15618
|
-
DirectionSchema =
|
|
15619
|
-
CategoryForecastSchema =
|
|
16373
|
+
DirectionSchema = z6.enum(["improving", "stable", "declining"]);
|
|
16374
|
+
CategoryForecastSchema = z6.object({
|
|
15620
16375
|
category: ArchMetricCategorySchema,
|
|
15621
|
-
current:
|
|
15622
|
-
threshold:
|
|
15623
|
-
projectedValue4w:
|
|
15624
|
-
projectedValue8w:
|
|
15625
|
-
projectedValue12w:
|
|
15626
|
-
thresholdCrossingWeeks:
|
|
16376
|
+
current: z6.number(),
|
|
16377
|
+
threshold: z6.number(),
|
|
16378
|
+
projectedValue4w: z6.number(),
|
|
16379
|
+
projectedValue8w: z6.number(),
|
|
16380
|
+
projectedValue12w: z6.number(),
|
|
16381
|
+
thresholdCrossingWeeks: z6.number().nullable(),
|
|
15627
16382
|
confidence: ConfidenceTierSchema,
|
|
15628
16383
|
regression: RegressionResultSchema,
|
|
15629
16384
|
direction: DirectionSchema
|
|
15630
16385
|
});
|
|
15631
|
-
SpecImpactSignalsSchema =
|
|
15632
|
-
newFileCount:
|
|
15633
|
-
affectedLayers:
|
|
15634
|
-
newDependencies:
|
|
15635
|
-
phaseCount:
|
|
16386
|
+
SpecImpactSignalsSchema = z6.object({
|
|
16387
|
+
newFileCount: z6.number().int().min(0),
|
|
16388
|
+
affectedLayers: z6.array(z6.string()),
|
|
16389
|
+
newDependencies: z6.number().int().min(0),
|
|
16390
|
+
phaseCount: z6.number().int().min(0)
|
|
15636
16391
|
});
|
|
15637
|
-
SpecImpactEstimateSchema =
|
|
15638
|
-
specPath:
|
|
15639
|
-
featureName:
|
|
16392
|
+
SpecImpactEstimateSchema = z6.object({
|
|
16393
|
+
specPath: z6.string(),
|
|
16394
|
+
featureName: z6.string(),
|
|
15640
16395
|
signals: SpecImpactSignalsSchema,
|
|
15641
|
-
deltas:
|
|
16396
|
+
deltas: z6.record(ArchMetricCategorySchema, z6.number()).optional()
|
|
15642
16397
|
});
|
|
15643
|
-
ContributingFeatureSchema =
|
|
15644
|
-
name:
|
|
15645
|
-
specPath:
|
|
15646
|
-
delta:
|
|
16398
|
+
ContributingFeatureSchema = z6.object({
|
|
16399
|
+
name: z6.string(),
|
|
16400
|
+
specPath: z6.string(),
|
|
16401
|
+
delta: z6.number()
|
|
15647
16402
|
});
|
|
15648
|
-
AdjustedForecastSchema =
|
|
16403
|
+
AdjustedForecastSchema = z6.object({
|
|
15649
16404
|
baseline: CategoryForecastSchema,
|
|
15650
16405
|
adjusted: CategoryForecastSchema,
|
|
15651
|
-
contributingFeatures:
|
|
16406
|
+
contributingFeatures: z6.array(ContributingFeatureSchema)
|
|
15652
16407
|
});
|
|
15653
|
-
PredictionWarningSchema =
|
|
15654
|
-
severity:
|
|
16408
|
+
PredictionWarningSchema = z6.object({
|
|
16409
|
+
severity: z6.enum(["critical", "warning", "info"]),
|
|
15655
16410
|
category: ArchMetricCategorySchema,
|
|
15656
|
-
message:
|
|
15657
|
-
weeksUntil:
|
|
16411
|
+
message: z6.string(),
|
|
16412
|
+
weeksUntil: z6.number(),
|
|
15658
16413
|
confidence: ConfidenceTierSchema,
|
|
15659
|
-
contributingFeatures:
|
|
16414
|
+
contributingFeatures: z6.array(z6.string())
|
|
15660
16415
|
});
|
|
15661
|
-
StabilityForecastSchema =
|
|
15662
|
-
current:
|
|
15663
|
-
projected4w:
|
|
15664
|
-
projected8w:
|
|
15665
|
-
projected12w:
|
|
16416
|
+
StabilityForecastSchema = z6.object({
|
|
16417
|
+
current: z6.number(),
|
|
16418
|
+
projected4w: z6.number(),
|
|
16419
|
+
projected8w: z6.number(),
|
|
16420
|
+
projected12w: z6.number(),
|
|
15666
16421
|
confidence: ConfidenceTierSchema,
|
|
15667
16422
|
direction: DirectionSchema
|
|
15668
16423
|
});
|
|
15669
|
-
PredictionResultSchema =
|
|
15670
|
-
generatedAt:
|
|
15671
|
-
snapshotsUsed:
|
|
15672
|
-
timelineRange:
|
|
15673
|
-
from:
|
|
15674
|
-
to:
|
|
16424
|
+
PredictionResultSchema = z6.object({
|
|
16425
|
+
generatedAt: z6.string(),
|
|
16426
|
+
snapshotsUsed: z6.number().int().min(0),
|
|
16427
|
+
timelineRange: z6.object({
|
|
16428
|
+
from: z6.string(),
|
|
16429
|
+
to: z6.string()
|
|
15675
16430
|
}),
|
|
15676
16431
|
stabilityForecast: StabilityForecastSchema,
|
|
15677
|
-
categories:
|
|
15678
|
-
warnings:
|
|
16432
|
+
categories: z6.record(ArchMetricCategorySchema, AdjustedForecastSchema),
|
|
16433
|
+
warnings: z6.array(PredictionWarningSchema)
|
|
15679
16434
|
});
|
|
15680
|
-
PredictionOptionsSchema =
|
|
15681
|
-
horizon:
|
|
15682
|
-
includeRoadmap:
|
|
15683
|
-
categories:
|
|
15684
|
-
thresholds:
|
|
16435
|
+
PredictionOptionsSchema = z6.object({
|
|
16436
|
+
horizon: z6.number().int().min(1).default(12),
|
|
16437
|
+
includeRoadmap: z6.boolean().default(true),
|
|
16438
|
+
categories: z6.array(ArchMetricCategorySchema).optional(),
|
|
16439
|
+
thresholds: z6.record(ArchMetricCategorySchema, z6.number()).optional()
|
|
15685
16440
|
});
|
|
15686
16441
|
VALID_STATUSES = /* @__PURE__ */ new Set([
|
|
15687
16442
|
"backlog",
|
|
@@ -16014,8 +16769,8 @@ var init_dist3 = __esm({
|
|
|
16014
16769
|
return null;
|
|
16015
16770
|
}
|
|
16016
16771
|
try {
|
|
16017
|
-
const roadmapPath =
|
|
16018
|
-
const raw =
|
|
16772
|
+
const roadmapPath = path4.join(this.rootDir, "roadmap.md");
|
|
16773
|
+
const raw = fs7.readFileSync(roadmapPath, "utf-8");
|
|
16019
16774
|
const parseResult = parseRoadmap(raw);
|
|
16020
16775
|
if (!parseResult.ok) return null;
|
|
16021
16776
|
const features = parseResult.value.milestones.flatMap(
|
|
@@ -16050,8 +16805,8 @@ var init_dist3 = __esm({
|
|
|
16050
16805
|
* @param specPath - Relative path from rootDir to the spec file.
|
|
16051
16806
|
*/
|
|
16052
16807
|
estimate(specPath) {
|
|
16053
|
-
const absolutePath =
|
|
16054
|
-
const content =
|
|
16808
|
+
const absolutePath = path5.join(this.rootDir, specPath);
|
|
16809
|
+
const content = fs8.readFileSync(absolutePath, "utf-8");
|
|
16055
16810
|
const newFileCount = this.extractNewFileCount(content);
|
|
16056
16811
|
const affectedLayers = this.extractAffectedLayers(content);
|
|
16057
16812
|
const newDependencies = this.extractNewDependencies(content);
|
|
@@ -16063,7 +16818,7 @@ var init_dist3 = __esm({
|
|
|
16063
16818
|
phaseCount
|
|
16064
16819
|
);
|
|
16065
16820
|
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
16066
|
-
const featureName = h1Match ? h1Match[1].trim() :
|
|
16821
|
+
const featureName = h1Match ? h1Match[1].trim() : path5.basename(specPath, ".md");
|
|
16067
16822
|
return {
|
|
16068
16823
|
specPath,
|
|
16069
16824
|
featureName,
|
|
@@ -16084,8 +16839,8 @@ var init_dist3 = __esm({
|
|
|
16084
16839
|
const results = [];
|
|
16085
16840
|
for (const feature of features) {
|
|
16086
16841
|
if (!feature.spec) continue;
|
|
16087
|
-
const absolutePath =
|
|
16088
|
-
if (!
|
|
16842
|
+
const absolutePath = path5.join(this.rootDir, feature.spec);
|
|
16843
|
+
if (!fs8.existsSync(absolutePath)) continue;
|
|
16089
16844
|
const estimate = this.estimate(feature.spec);
|
|
16090
16845
|
results.push({ ...estimate, featureName: feature.name });
|
|
16091
16846
|
}
|
|
@@ -16113,8 +16868,8 @@ var init_dist3 = __esm({
|
|
|
16113
16868
|
}
|
|
16114
16869
|
let count = 0;
|
|
16115
16870
|
for (const fp of filePaths) {
|
|
16116
|
-
const absolute =
|
|
16117
|
-
if (!
|
|
16871
|
+
const absolute = path5.join(this.rootDir, fp);
|
|
16872
|
+
if (!fs8.existsSync(absolute)) {
|
|
16118
16873
|
count++;
|
|
16119
16874
|
}
|
|
16120
16875
|
}
|
|
@@ -16184,8 +16939,8 @@ var init_dist3 = __esm({
|
|
|
16184
16939
|
// --- Private: Config Loading ---
|
|
16185
16940
|
loadLayerNames() {
|
|
16186
16941
|
try {
|
|
16187
|
-
const configPath =
|
|
16188
|
-
const raw =
|
|
16942
|
+
const configPath = path5.join(this.rootDir, "harness.config.json");
|
|
16943
|
+
const raw = fs8.readFileSync(configPath, "utf-8");
|
|
16189
16944
|
const config = JSON.parse(raw);
|
|
16190
16945
|
return (config.layers ?? []).map((l) => l.name);
|
|
16191
16946
|
} catch {
|
|
@@ -16204,8 +16959,8 @@ var init_dist3 = __esm({
|
|
|
16204
16959
|
historyPath;
|
|
16205
16960
|
/** Load history from disk, returning empty history if file doesn't exist. */
|
|
16206
16961
|
load() {
|
|
16207
|
-
if (!
|
|
16208
|
-
const raw =
|
|
16962
|
+
if (!fs9.existsSync(this.historyPath)) return { ...EMPTY_HISTORY, snapshots: [] };
|
|
16963
|
+
const raw = fs9.readFileSync(this.historyPath, "utf-8");
|
|
16209
16964
|
return JSON.parse(raw);
|
|
16210
16965
|
}
|
|
16211
16966
|
/** Append a timestamped snapshot of current violations. */
|
|
@@ -16219,18 +16974,18 @@ var init_dist3 = __esm({
|
|
|
16219
16974
|
}
|
|
16220
16975
|
/** Prune snapshots older than retentionDays. */
|
|
16221
16976
|
prune(retentionDays) {
|
|
16222
|
-
if (!
|
|
16977
|
+
if (!fs9.existsSync(this.historyPath)) return;
|
|
16223
16978
|
const history = this.load();
|
|
16224
16979
|
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
16225
16980
|
history.snapshots = history.snapshots.filter((s) => new Date(s.timestamp).getTime() >= cutoff);
|
|
16226
16981
|
this.write(history);
|
|
16227
16982
|
}
|
|
16228
16983
|
write(history) {
|
|
16229
|
-
const dir =
|
|
16230
|
-
if (!
|
|
16231
|
-
|
|
16984
|
+
const dir = path6.dirname(this.historyPath);
|
|
16985
|
+
if (!fs9.existsSync(dir)) {
|
|
16986
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
16232
16987
|
}
|
|
16233
|
-
|
|
16988
|
+
fs9.writeFileSync(this.historyPath, JSON.stringify(history, null, 2), "utf-8");
|
|
16234
16989
|
}
|
|
16235
16990
|
};
|
|
16236
16991
|
NORMALIZERS = {
|
|
@@ -16245,81 +17000,81 @@ var init_dist3 = __esm({
|
|
|
16245
17000
|
MAX_SAMPLES = 5;
|
|
16246
17001
|
DEFAULT_WINDOW_WEEKS = 4;
|
|
16247
17002
|
DEFAULT_MIN_OCCURRENCES = 3;
|
|
16248
|
-
FailureEntrySchema =
|
|
16249
|
-
date:
|
|
16250
|
-
skill:
|
|
16251
|
-
type:
|
|
16252
|
-
description:
|
|
17003
|
+
FailureEntrySchema = z7.object({
|
|
17004
|
+
date: z7.string(),
|
|
17005
|
+
skill: z7.string(),
|
|
17006
|
+
type: z7.string(),
|
|
17007
|
+
description: z7.string()
|
|
16253
17008
|
});
|
|
16254
|
-
HandoffSchema =
|
|
16255
|
-
timestamp:
|
|
16256
|
-
fromSkill:
|
|
16257
|
-
phase:
|
|
16258
|
-
summary:
|
|
16259
|
-
completed:
|
|
16260
|
-
pending:
|
|
16261
|
-
concerns:
|
|
16262
|
-
decisions:
|
|
16263
|
-
|
|
16264
|
-
what:
|
|
16265
|
-
why:
|
|
17009
|
+
HandoffSchema = z7.object({
|
|
17010
|
+
timestamp: z7.string(),
|
|
17011
|
+
fromSkill: z7.string(),
|
|
17012
|
+
phase: z7.string(),
|
|
17013
|
+
summary: z7.string(),
|
|
17014
|
+
completed: z7.array(z7.string()).default([]),
|
|
17015
|
+
pending: z7.array(z7.string()).default([]),
|
|
17016
|
+
concerns: z7.array(z7.string()).default([]),
|
|
17017
|
+
decisions: z7.array(
|
|
17018
|
+
z7.object({
|
|
17019
|
+
what: z7.string(),
|
|
17020
|
+
why: z7.string()
|
|
16266
17021
|
})
|
|
16267
17022
|
).default([]),
|
|
16268
|
-
blockers:
|
|
16269
|
-
contextKeywords:
|
|
16270
|
-
recommendedSkills:
|
|
16271
|
-
apply:
|
|
16272
|
-
reference:
|
|
16273
|
-
consider:
|
|
16274
|
-
skillsPath:
|
|
17023
|
+
blockers: z7.array(z7.string()).default([]),
|
|
17024
|
+
contextKeywords: z7.array(z7.string()).default([]),
|
|
17025
|
+
recommendedSkills: z7.object({
|
|
17026
|
+
apply: z7.array(z7.string()),
|
|
17027
|
+
reference: z7.array(z7.string()),
|
|
17028
|
+
consider: z7.array(z7.string()),
|
|
17029
|
+
skillsPath: z7.string()
|
|
16275
17030
|
}).optional()
|
|
16276
17031
|
});
|
|
16277
|
-
GateCheckSchema =
|
|
16278
|
-
name:
|
|
16279
|
-
passed:
|
|
16280
|
-
command:
|
|
16281
|
-
output:
|
|
16282
|
-
duration:
|
|
17032
|
+
GateCheckSchema = z7.object({
|
|
17033
|
+
name: z7.string(),
|
|
17034
|
+
passed: z7.boolean(),
|
|
17035
|
+
command: z7.string(),
|
|
17036
|
+
output: z7.string().optional(),
|
|
17037
|
+
duration: z7.number().optional()
|
|
16283
17038
|
});
|
|
16284
|
-
GateResultSchema =
|
|
16285
|
-
passed:
|
|
16286
|
-
checks:
|
|
17039
|
+
GateResultSchema = z7.object({
|
|
17040
|
+
passed: z7.boolean(),
|
|
17041
|
+
checks: z7.array(GateCheckSchema)
|
|
16287
17042
|
});
|
|
16288
|
-
GateConfigSchema =
|
|
16289
|
-
checks:
|
|
16290
|
-
|
|
16291
|
-
name:
|
|
16292
|
-
command:
|
|
17043
|
+
GateConfigSchema = z7.object({
|
|
17044
|
+
checks: z7.array(
|
|
17045
|
+
z7.object({
|
|
17046
|
+
name: z7.string(),
|
|
17047
|
+
command: z7.string()
|
|
16293
17048
|
})
|
|
16294
17049
|
).optional(),
|
|
16295
|
-
trace:
|
|
17050
|
+
trace: z7.boolean().optional()
|
|
16296
17051
|
});
|
|
16297
|
-
HarnessStateSchema =
|
|
16298
|
-
schemaVersion:
|
|
16299
|
-
position:
|
|
16300
|
-
phase:
|
|
16301
|
-
task:
|
|
17052
|
+
HarnessStateSchema = z7.object({
|
|
17053
|
+
schemaVersion: z7.literal(1),
|
|
17054
|
+
position: z7.object({
|
|
17055
|
+
phase: z7.string().optional(),
|
|
17056
|
+
task: z7.string().optional()
|
|
16302
17057
|
}).default({}),
|
|
16303
|
-
decisions:
|
|
16304
|
-
|
|
16305
|
-
date:
|
|
16306
|
-
decision:
|
|
16307
|
-
context:
|
|
17058
|
+
decisions: z7.array(
|
|
17059
|
+
z7.object({
|
|
17060
|
+
date: z7.string(),
|
|
17061
|
+
decision: z7.string(),
|
|
17062
|
+
context: z7.string()
|
|
16308
17063
|
})
|
|
16309
17064
|
).default([]),
|
|
16310
|
-
blockers:
|
|
16311
|
-
|
|
16312
|
-
id:
|
|
16313
|
-
description:
|
|
16314
|
-
status:
|
|
17065
|
+
blockers: z7.array(
|
|
17066
|
+
z7.object({
|
|
17067
|
+
id: z7.string(),
|
|
17068
|
+
description: z7.string(),
|
|
17069
|
+
status: z7.enum(["open", "resolved"])
|
|
16315
17070
|
})
|
|
16316
17071
|
).default([]),
|
|
16317
|
-
progress:
|
|
16318
|
-
lastSession:
|
|
16319
|
-
date:
|
|
16320
|
-
summary:
|
|
16321
|
-
lastSkill:
|
|
16322
|
-
pendingTasks:
|
|
17072
|
+
progress: z7.record(z7.enum(["pending", "in_progress", "complete"])).default({}),
|
|
17073
|
+
lastSession: z7.object({
|
|
17074
|
+
date: z7.string(),
|
|
17075
|
+
summary: z7.string(),
|
|
17076
|
+
lastSkill: z7.string().optional(),
|
|
17077
|
+
pendingTasks: z7.array(z7.string()).optional()
|
|
16323
17078
|
}).optional()
|
|
16324
17079
|
});
|
|
16325
17080
|
DEFAULT_STATE = {
|
|
@@ -16329,16 +17084,16 @@ var init_dist3 = __esm({
|
|
|
16329
17084
|
blockers: [],
|
|
16330
17085
|
progress: {}
|
|
16331
17086
|
};
|
|
16332
|
-
StreamInfoSchema =
|
|
16333
|
-
name:
|
|
16334
|
-
branch:
|
|
16335
|
-
createdAt:
|
|
16336
|
-
lastActiveAt:
|
|
17087
|
+
StreamInfoSchema = z8.object({
|
|
17088
|
+
name: z8.string(),
|
|
17089
|
+
branch: z8.string().optional(),
|
|
17090
|
+
createdAt: z8.string(),
|
|
17091
|
+
lastActiveAt: z8.string()
|
|
16337
17092
|
});
|
|
16338
|
-
StreamIndexSchema =
|
|
16339
|
-
schemaVersion:
|
|
16340
|
-
activeStream:
|
|
16341
|
-
streams:
|
|
17093
|
+
StreamIndexSchema = z8.object({
|
|
17094
|
+
schemaVersion: z8.literal(1),
|
|
17095
|
+
activeStream: z8.string().nullable(),
|
|
17096
|
+
streams: z8.record(StreamInfoSchema)
|
|
16342
17097
|
});
|
|
16343
17098
|
DEFAULT_STREAM_INDEX = {
|
|
16344
17099
|
schemaVersion: 1,
|
|
@@ -16379,15 +17134,15 @@ var init_dist3 = __esm({
|
|
|
16379
17134
|
failuresCacheMap = /* @__PURE__ */ new Map();
|
|
16380
17135
|
FAILURE_LINE_REGEX = /^- \*\*(\d{4}-\d{2}-\d{2}) \[skill:([^\]]+)\] \[type:([^\]]+)\]:\*\* (.+)$/;
|
|
16381
17136
|
SAFE_GATE_COMMAND = /^(?:npm|pnpm|yarn)\s+(?:test|run\s+[\w.-]+|run-script\s+[\w.-]+)$|^go\s+(?:test|build|vet|fmt)\s+[\w./ -]+$|^(?:python|python3)\s+-m\s+[\w.-]+$|^make\s+[\w.-]+$|^cargo\s+(?:test|build|check|clippy)(?:\s+[\w./ -]+)?$|^(?:gradle|mvn)\s+[\w:.-]+$/;
|
|
16382
|
-
SkillEventSchema =
|
|
16383
|
-
timestamp:
|
|
16384
|
-
skill:
|
|
16385
|
-
session:
|
|
16386
|
-
type:
|
|
16387
|
-
summary:
|
|
16388
|
-
data:
|
|
16389
|
-
refs:
|
|
16390
|
-
contentHash:
|
|
17137
|
+
SkillEventSchema = z9.object({
|
|
17138
|
+
timestamp: z9.string(),
|
|
17139
|
+
skill: z9.string(),
|
|
17140
|
+
session: z9.string().optional(),
|
|
17141
|
+
type: z9.enum(["phase_transition", "decision", "gate_result", "handoff", "error", "checkpoint"]),
|
|
17142
|
+
summary: z9.string(),
|
|
17143
|
+
data: z9.record(z9.unknown()).optional(),
|
|
17144
|
+
refs: z9.array(z9.string()).optional(),
|
|
17145
|
+
contentHash: z9.string().optional()
|
|
16391
17146
|
});
|
|
16392
17147
|
knownHashesCache = /* @__PURE__ */ new Map();
|
|
16393
17148
|
EVENT_FORMATTERS = {
|
|
@@ -16430,19 +17185,19 @@ var init_dist3 = __esm({
|
|
|
16430
17185
|
rules: {},
|
|
16431
17186
|
exclude: ["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]
|
|
16432
17187
|
};
|
|
16433
|
-
RuleOverrideSchema =
|
|
16434
|
-
SecurityConfigSchema =
|
|
16435
|
-
enabled:
|
|
16436
|
-
strict:
|
|
16437
|
-
rules:
|
|
16438
|
-
exclude:
|
|
16439
|
-
external:
|
|
16440
|
-
semgrep:
|
|
16441
|
-
enabled:
|
|
16442
|
-
rulesets:
|
|
17188
|
+
RuleOverrideSchema = z10.enum(["off", "error", "warning", "info"]);
|
|
17189
|
+
SecurityConfigSchema = z10.object({
|
|
17190
|
+
enabled: z10.boolean().default(true),
|
|
17191
|
+
strict: z10.boolean().default(false),
|
|
17192
|
+
rules: z10.record(z10.string(), RuleOverrideSchema).optional().default({}),
|
|
17193
|
+
exclude: z10.array(z10.string()).optional().default(["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]),
|
|
17194
|
+
external: z10.object({
|
|
17195
|
+
semgrep: z10.object({
|
|
17196
|
+
enabled: z10.union([z10.literal("auto"), z10.boolean()]).default("auto"),
|
|
17197
|
+
rulesets: z10.array(z10.string()).optional()
|
|
16443
17198
|
}).optional(),
|
|
16444
|
-
gitleaks:
|
|
16445
|
-
enabled:
|
|
17199
|
+
gitleaks: z10.object({
|
|
17200
|
+
enabled: z10.union([z10.literal("auto"), z10.boolean()]).default("auto")
|
|
16446
17201
|
}).optional()
|
|
16447
17202
|
}).optional()
|
|
16448
17203
|
});
|
|
@@ -17232,7 +17987,7 @@ var init_dist3 = __esm({
|
|
|
17232
17987
|
}
|
|
17233
17988
|
async scanFile(filePath) {
|
|
17234
17989
|
if (!this.config.enabled) return [];
|
|
17235
|
-
const content = await
|
|
17990
|
+
const content = await fs27.readFile(filePath, "utf-8");
|
|
17236
17991
|
return this.scanContentForFile(content, filePath, 1);
|
|
17237
17992
|
}
|
|
17238
17993
|
scanContentForFile(content, filePath, startLine = 1) {
|
|
@@ -17541,88 +18296,88 @@ var init_dist3 = __esm({
|
|
|
17541
18296
|
];
|
|
17542
18297
|
TAINT_DURATION_MS = 30 * 60 * 1e3;
|
|
17543
18298
|
DEFAULT_SESSION_ID = "default";
|
|
17544
|
-
SecurityCategorySnapshotSchema =
|
|
17545
|
-
findingCount:
|
|
17546
|
-
errorCount:
|
|
17547
|
-
warningCount:
|
|
17548
|
-
infoCount:
|
|
18299
|
+
SecurityCategorySnapshotSchema = z11.object({
|
|
18300
|
+
findingCount: z11.number(),
|
|
18301
|
+
errorCount: z11.number(),
|
|
18302
|
+
warningCount: z11.number(),
|
|
18303
|
+
infoCount: z11.number()
|
|
17549
18304
|
});
|
|
17550
|
-
SupplyChainSnapshotSchema =
|
|
17551
|
-
critical:
|
|
17552
|
-
high:
|
|
17553
|
-
moderate:
|
|
17554
|
-
low:
|
|
17555
|
-
info:
|
|
17556
|
-
total:
|
|
18305
|
+
SupplyChainSnapshotSchema = z11.object({
|
|
18306
|
+
critical: z11.number(),
|
|
18307
|
+
high: z11.number(),
|
|
18308
|
+
moderate: z11.number(),
|
|
18309
|
+
low: z11.number(),
|
|
18310
|
+
info: z11.number(),
|
|
18311
|
+
total: z11.number()
|
|
17557
18312
|
});
|
|
17558
|
-
SecurityTimelineSnapshotSchema =
|
|
17559
|
-
capturedAt:
|
|
17560
|
-
commitHash:
|
|
17561
|
-
securityScore:
|
|
17562
|
-
totalFindings:
|
|
17563
|
-
bySeverity:
|
|
17564
|
-
error:
|
|
17565
|
-
warning:
|
|
17566
|
-
info:
|
|
18313
|
+
SecurityTimelineSnapshotSchema = z11.object({
|
|
18314
|
+
capturedAt: z11.string().datetime(),
|
|
18315
|
+
commitHash: z11.string(),
|
|
18316
|
+
securityScore: z11.number().min(0).max(100),
|
|
18317
|
+
totalFindings: z11.number(),
|
|
18318
|
+
bySeverity: z11.object({
|
|
18319
|
+
error: z11.number(),
|
|
18320
|
+
warning: z11.number(),
|
|
18321
|
+
info: z11.number()
|
|
17567
18322
|
}),
|
|
17568
|
-
byCategory:
|
|
18323
|
+
byCategory: z11.record(z11.string(), SecurityCategorySnapshotSchema),
|
|
17569
18324
|
supplyChain: SupplyChainSnapshotSchema,
|
|
17570
|
-
suppressionCount:
|
|
17571
|
-
findingIds:
|
|
18325
|
+
suppressionCount: z11.number(),
|
|
18326
|
+
findingIds: z11.array(z11.string())
|
|
17572
18327
|
});
|
|
17573
|
-
FindingLifecycleSchema =
|
|
17574
|
-
findingId:
|
|
17575
|
-
ruleId:
|
|
17576
|
-
category:
|
|
17577
|
-
severity:
|
|
17578
|
-
file:
|
|
17579
|
-
firstSeenAt:
|
|
17580
|
-
firstSeenCommit:
|
|
17581
|
-
resolvedAt:
|
|
17582
|
-
resolvedCommit:
|
|
18328
|
+
FindingLifecycleSchema = z11.object({
|
|
18329
|
+
findingId: z11.string(),
|
|
18330
|
+
ruleId: z11.string(),
|
|
18331
|
+
category: z11.string(),
|
|
18332
|
+
severity: z11.string(),
|
|
18333
|
+
file: z11.string(),
|
|
18334
|
+
firstSeenAt: z11.string().datetime(),
|
|
18335
|
+
firstSeenCommit: z11.string(),
|
|
18336
|
+
resolvedAt: z11.string().datetime().nullable(),
|
|
18337
|
+
resolvedCommit: z11.string().nullable()
|
|
17583
18338
|
});
|
|
17584
|
-
SecurityTimelineFileSchema =
|
|
17585
|
-
version:
|
|
17586
|
-
snapshots:
|
|
17587
|
-
findingLifecycles:
|
|
18339
|
+
SecurityTimelineFileSchema = z11.object({
|
|
18340
|
+
version: z11.literal(1),
|
|
18341
|
+
snapshots: z11.array(SecurityTimelineSnapshotSchema),
|
|
18342
|
+
findingLifecycles: z11.array(FindingLifecycleSchema)
|
|
17588
18343
|
});
|
|
17589
|
-
DirectionSchema2 =
|
|
17590
|
-
SecurityTrendLineSchema =
|
|
17591
|
-
current:
|
|
17592
|
-
previous:
|
|
17593
|
-
delta:
|
|
18344
|
+
DirectionSchema2 = z11.enum(["improving", "stable", "declining"]);
|
|
18345
|
+
SecurityTrendLineSchema = z11.object({
|
|
18346
|
+
current: z11.number(),
|
|
18347
|
+
previous: z11.number(),
|
|
18348
|
+
delta: z11.number(),
|
|
17594
18349
|
direction: DirectionSchema2
|
|
17595
18350
|
});
|
|
17596
|
-
TrendAttributionSchema =
|
|
17597
|
-
category:
|
|
17598
|
-
delta:
|
|
18351
|
+
TrendAttributionSchema = z11.object({
|
|
18352
|
+
category: z11.string(),
|
|
18353
|
+
delta: z11.number(),
|
|
17599
18354
|
direction: DirectionSchema2,
|
|
17600
|
-
description:
|
|
18355
|
+
description: z11.string()
|
|
17601
18356
|
});
|
|
17602
|
-
SecurityTrendResultSchema =
|
|
18357
|
+
SecurityTrendResultSchema = z11.object({
|
|
17603
18358
|
score: SecurityTrendLineSchema,
|
|
17604
18359
|
totalFindings: SecurityTrendLineSchema,
|
|
17605
|
-
bySeverity:
|
|
18360
|
+
bySeverity: z11.object({
|
|
17606
18361
|
error: SecurityTrendLineSchema,
|
|
17607
18362
|
warning: SecurityTrendLineSchema,
|
|
17608
18363
|
info: SecurityTrendLineSchema
|
|
17609
18364
|
}),
|
|
17610
18365
|
supplyChain: SecurityTrendLineSchema,
|
|
17611
|
-
snapshotCount:
|
|
17612
|
-
from:
|
|
17613
|
-
to:
|
|
17614
|
-
attribution:
|
|
18366
|
+
snapshotCount: z11.number(),
|
|
18367
|
+
from: z11.string(),
|
|
18368
|
+
to: z11.string(),
|
|
18369
|
+
attribution: z11.array(TrendAttributionSchema)
|
|
17615
18370
|
});
|
|
17616
|
-
TimeToFixStatsSchema =
|
|
17617
|
-
mean:
|
|
17618
|
-
median:
|
|
17619
|
-
count:
|
|
18371
|
+
TimeToFixStatsSchema = z11.object({
|
|
18372
|
+
mean: z11.number(),
|
|
18373
|
+
median: z11.number(),
|
|
18374
|
+
count: z11.number()
|
|
17620
18375
|
});
|
|
17621
|
-
TimeToFixResultSchema =
|
|
18376
|
+
TimeToFixResultSchema = z11.object({
|
|
17622
18377
|
overall: TimeToFixStatsSchema,
|
|
17623
|
-
byCategory:
|
|
17624
|
-
openFindings:
|
|
17625
|
-
oldestOpenDays:
|
|
18378
|
+
byCategory: z11.record(z11.string(), TimeToFixStatsSchema),
|
|
18379
|
+
openFindings: z11.number(),
|
|
18380
|
+
oldestOpenDays: z11.number().nullable()
|
|
17626
18381
|
});
|
|
17627
18382
|
EMPTY_SUPPLY_CHAIN = {
|
|
17628
18383
|
critical: 0,
|
|
@@ -17637,7 +18392,7 @@ var init_dist3 = __esm({
|
|
|
17637
18392
|
timelinePath;
|
|
17638
18393
|
constructor(rootDir) {
|
|
17639
18394
|
this.rootDir = rootDir;
|
|
17640
|
-
this.timelinePath =
|
|
18395
|
+
this.timelinePath = join39(rootDir, ".harness", "security", "timeline.json");
|
|
17641
18396
|
}
|
|
17642
18397
|
/**
|
|
17643
18398
|
* Load timeline from disk.
|
|
@@ -18015,8 +18770,8 @@ var init_dist3 = __esm({
|
|
|
18015
18770
|
skip: "\u23ED\uFE0F"
|
|
18016
18771
|
};
|
|
18017
18772
|
CINotifier = class {
|
|
18018
|
-
constructor(
|
|
18019
|
-
this.adapter =
|
|
18773
|
+
constructor(adapter2, repo) {
|
|
18774
|
+
this.adapter = adapter2;
|
|
18020
18775
|
this.repo = repo;
|
|
18021
18776
|
}
|
|
18022
18777
|
adapter;
|
|
@@ -18667,28 +19422,28 @@ var init_dist3 = __esm({
|
|
|
18667
19422
|
POSITION_WEIGHT = 0.5;
|
|
18668
19423
|
DEPENDENTS_WEIGHT = 0.3;
|
|
18669
19424
|
AFFINITY_WEIGHT = 0.2;
|
|
18670
|
-
InteractionTypeSchema =
|
|
18671
|
-
QuestionSchema =
|
|
18672
|
-
text:
|
|
18673
|
-
options:
|
|
18674
|
-
default:
|
|
19425
|
+
InteractionTypeSchema = z12.enum(["question", "confirmation", "transition"]);
|
|
19426
|
+
QuestionSchema = z12.object({
|
|
19427
|
+
text: z12.string(),
|
|
19428
|
+
options: z12.array(z12.string()).optional(),
|
|
19429
|
+
default: z12.string().optional()
|
|
18675
19430
|
});
|
|
18676
|
-
ConfirmationSchema =
|
|
18677
|
-
text:
|
|
18678
|
-
context:
|
|
19431
|
+
ConfirmationSchema = z12.object({
|
|
19432
|
+
text: z12.string(),
|
|
19433
|
+
context: z12.string()
|
|
18679
19434
|
});
|
|
18680
|
-
TransitionSchema =
|
|
18681
|
-
completedPhase:
|
|
18682
|
-
suggestedNext:
|
|
18683
|
-
reason:
|
|
18684
|
-
artifacts:
|
|
18685
|
-
requiresConfirmation:
|
|
18686
|
-
summary:
|
|
19435
|
+
TransitionSchema = z12.object({
|
|
19436
|
+
completedPhase: z12.string(),
|
|
19437
|
+
suggestedNext: z12.string(),
|
|
19438
|
+
reason: z12.string(),
|
|
19439
|
+
artifacts: z12.array(z12.string()),
|
|
19440
|
+
requiresConfirmation: z12.boolean(),
|
|
19441
|
+
summary: z12.string()
|
|
18687
19442
|
});
|
|
18688
|
-
EmitInteractionInputSchema =
|
|
18689
|
-
path:
|
|
19443
|
+
EmitInteractionInputSchema = z12.object({
|
|
19444
|
+
path: z12.string(),
|
|
18690
19445
|
type: InteractionTypeSchema,
|
|
18691
|
-
stream:
|
|
19446
|
+
stream: z12.string().optional(),
|
|
18692
19447
|
question: QuestionSchema.optional(),
|
|
18693
19448
|
confirmation: ConfirmationSchema.optional(),
|
|
18694
19449
|
transition: TransitionSchema.optional()
|
|
@@ -18699,10 +19454,10 @@ var init_dist3 = __esm({
|
|
|
18699
19454
|
}
|
|
18700
19455
|
rootDir;
|
|
18701
19456
|
async scan() {
|
|
18702
|
-
let projectName =
|
|
19457
|
+
let projectName = path30.basename(this.rootDir);
|
|
18703
19458
|
try {
|
|
18704
|
-
const pkgPath =
|
|
18705
|
-
const pkgRaw = await
|
|
19459
|
+
const pkgPath = path30.join(this.rootDir, "package.json");
|
|
19460
|
+
const pkgRaw = await fs31.readFile(pkgPath, "utf-8");
|
|
18706
19461
|
const pkg = JSON.parse(pkgRaw);
|
|
18707
19462
|
if (pkg.name) projectName = pkg.name;
|
|
18708
19463
|
} catch {
|
|
@@ -18815,8 +19570,8 @@ console.log('Blueprint player initialized.');
|
|
|
18815
19570
|
styles: STYLES,
|
|
18816
19571
|
scripts: SCRIPTS
|
|
18817
19572
|
});
|
|
18818
|
-
await
|
|
18819
|
-
await
|
|
19573
|
+
await fs32.mkdir(options.outputDir, { recursive: true });
|
|
19574
|
+
await fs32.writeFile(path31.join(options.outputDir, "index.html"), html);
|
|
18820
19575
|
}
|
|
18821
19576
|
};
|
|
18822
19577
|
TOKENS_PER_MILLION = 1e6;
|
|
@@ -19039,6 +19794,145 @@ console.log('Blueprint player initialized.');
|
|
|
19039
19794
|
POSTHOG_BATCH_URL = "https://app.posthog.com/batch";
|
|
19040
19795
|
MAX_ATTEMPTS = 3;
|
|
19041
19796
|
TIMEOUT_MS = 5e3;
|
|
19797
|
+
CompoundLockHeldError = class extends Error {
|
|
19798
|
+
constructor(category, holderPid, lockPath) {
|
|
19799
|
+
super(
|
|
19800
|
+
`Compound lock for category "${category}" is held by pid ${holderPid} (lock file: ${lockPath}). If the holder is no longer running (e.g. it was SIGKILL'd), the lock is stale; recover with: rm ${lockPath}`
|
|
19801
|
+
);
|
|
19802
|
+
this.category = category;
|
|
19803
|
+
this.holderPid = holderPid;
|
|
19804
|
+
this.lockPath = lockPath;
|
|
19805
|
+
this.name = "CompoundLockHeldError";
|
|
19806
|
+
}
|
|
19807
|
+
category;
|
|
19808
|
+
holderPid;
|
|
19809
|
+
lockPath;
|
|
19810
|
+
};
|
|
19811
|
+
KNOWN_CATEGORIES = new Set(ALL_SOLUTION_CATEGORIES);
|
|
19812
|
+
ALLOWED_FIELD_KEYS = [
|
|
19813
|
+
"event_name",
|
|
19814
|
+
"count",
|
|
19815
|
+
"timestamp_bucket",
|
|
19816
|
+
"error_signature",
|
|
19817
|
+
"latency_ms",
|
|
19818
|
+
"category"
|
|
19819
|
+
];
|
|
19820
|
+
PII_TOKENS = [
|
|
19821
|
+
"email",
|
|
19822
|
+
"user_id",
|
|
19823
|
+
"session_id",
|
|
19824
|
+
"ip",
|
|
19825
|
+
"name",
|
|
19826
|
+
"phone",
|
|
19827
|
+
"address",
|
|
19828
|
+
"message",
|
|
19829
|
+
"content",
|
|
19830
|
+
"payload"
|
|
19831
|
+
];
|
|
19832
|
+
PII_FIELD_DENYLIST = new RegExp(`^(?:${PII_TOKENS.join("|")})$`, "i");
|
|
19833
|
+
PII_LINE_RE = new RegExp(`\\b(?:${PII_TOKENS.join("|")})\\b`, "i");
|
|
19834
|
+
ALLOWED_SET = new Set(ALLOWED_FIELD_KEYS);
|
|
19835
|
+
PulseAdapterAlreadyRegisteredError = class extends Error {
|
|
19836
|
+
constructor(adapterName) {
|
|
19837
|
+
super(`Pulse adapter "${adapterName}" is already registered.`);
|
|
19838
|
+
this.adapterName = adapterName;
|
|
19839
|
+
this.name = "PulseAdapterAlreadyRegisteredError";
|
|
19840
|
+
}
|
|
19841
|
+
adapterName;
|
|
19842
|
+
};
|
|
19843
|
+
REGISTRY = /* @__PURE__ */ new Map();
|
|
19844
|
+
MOCK_ADAPTER_NAME = "mock";
|
|
19845
|
+
ALLOWED_FIELD_SET = new Set(ALLOWED_FIELD_KEYS);
|
|
19846
|
+
adapter = {
|
|
19847
|
+
async query(_window, _eventNames) {
|
|
19848
|
+
return {
|
|
19849
|
+
event_name: "mock.event",
|
|
19850
|
+
count: 42,
|
|
19851
|
+
timestamp_bucket: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
19852
|
+
latency_ms: 123
|
|
19853
|
+
};
|
|
19854
|
+
},
|
|
19855
|
+
sanitize(raw) {
|
|
19856
|
+
const fields = {};
|
|
19857
|
+
if (raw && typeof raw === "object") {
|
|
19858
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
19859
|
+
if (PII_FIELD_DENYLIST.test(key)) continue;
|
|
19860
|
+
if (!ALLOWED_FIELD_SET.has(key)) continue;
|
|
19861
|
+
fields[key] = value;
|
|
19862
|
+
}
|
|
19863
|
+
}
|
|
19864
|
+
return { fields, distributions: {} };
|
|
19865
|
+
}
|
|
19866
|
+
};
|
|
19867
|
+
registerMockAdapter();
|
|
19868
|
+
LOOKBACK_RE = /^(\d+)(h|d)$/;
|
|
19869
|
+
MAX_LINES = 40;
|
|
19870
|
+
INLINE_TEMPLATE = `# {{productName}} Pulse \u2014 {{windowLabel}}
|
|
19871
|
+
|
|
19872
|
+
## Headlines
|
|
19873
|
+
|
|
19874
|
+
{{headlines}}
|
|
19875
|
+
|
|
19876
|
+
## Usage
|
|
19877
|
+
|
|
19878
|
+
{{usage}}
|
|
19879
|
+
|
|
19880
|
+
## System performance
|
|
19881
|
+
|
|
19882
|
+
{{systemPerformance}}
|
|
19883
|
+
|
|
19884
|
+
## Followups
|
|
19885
|
+
|
|
19886
|
+
{{followups}}
|
|
19887
|
+
`;
|
|
19888
|
+
TRUNCATION_MARKER2 = "_(truncated to fit single-page constraint)_";
|
|
19889
|
+
execFileAsync = promisify22(execFile);
|
|
19890
|
+
FIX_RE = /^fix(\([^)]+\))?:/i;
|
|
19891
|
+
EMPTY_REPO_RE = /(does not have any commits yet|not a git repository)/i;
|
|
19892
|
+
execFileAsync2 = promisify3(execFile2);
|
|
19893
|
+
TRACK_CATEGORIES2 = [
|
|
19894
|
+
["bug-track", BUG_TRACK_CATEGORIES],
|
|
19895
|
+
["knowledge-track", KNOWLEDGE_TRACK_CATEGORIES]
|
|
19896
|
+
];
|
|
19897
|
+
STOPWORDS = /* @__PURE__ */ new Set([
|
|
19898
|
+
"fix",
|
|
19899
|
+
"the",
|
|
19900
|
+
"a",
|
|
19901
|
+
"an",
|
|
19902
|
+
"in",
|
|
19903
|
+
"on",
|
|
19904
|
+
"of",
|
|
19905
|
+
"and",
|
|
19906
|
+
"or",
|
|
19907
|
+
"to",
|
|
19908
|
+
"for",
|
|
19909
|
+
"with",
|
|
19910
|
+
"is",
|
|
19911
|
+
"be",
|
|
19912
|
+
"when",
|
|
19913
|
+
"if",
|
|
19914
|
+
"this",
|
|
19915
|
+
"that",
|
|
19916
|
+
"edge",
|
|
19917
|
+
"case",
|
|
19918
|
+
"handle"
|
|
19919
|
+
]);
|
|
19920
|
+
KEYWORD_TO_CATEGORY = [
|
|
19921
|
+
[/\b(test|flaky|spec)\b/i, "bug-track/test-failures"],
|
|
19922
|
+
[/\b(perf|slow|latency|throughput|timeout|deadlock|n\+1|oom)\b/i, "bug-track/performance-issues"],
|
|
19923
|
+
[
|
|
19924
|
+
/\b(security|sqli|injection|xss|csrf|jwt|oauth|auth(?:n|z|entication)?|crypt(?:o|ographic|ography)?|encrypt(?:ion)?|decrypt(?:ion)?|password|token|session|tls|ssl)\b/i,
|
|
19925
|
+
"bug-track/security-issues"
|
|
19926
|
+
],
|
|
19927
|
+
[/\b(ui|css|color|contrast|layout|render)\b/i, "bug-track/ui-bugs"],
|
|
19928
|
+
[/\b(build|compile|tsc|webpack|tsup)\b/i, "bug-track/build-errors"],
|
|
19929
|
+
[
|
|
19930
|
+
/\b(db|database|sql|postgres|mysql|query|migration|transaction|deadlock)\b/i,
|
|
19931
|
+
"bug-track/database-issues"
|
|
19932
|
+
],
|
|
19933
|
+
[/\b(runtime|crash|exception|panic)\b/i, "bug-track/runtime-errors"],
|
|
19934
|
+
[/\(orchestrator\)|\bintegrat|\blease\b|\brace\b|\bconcurren/i, "bug-track/integration-issues"]
|
|
19935
|
+
];
|
|
19042
19936
|
}
|
|
19043
19937
|
});
|
|
19044
19938
|
|
|
@@ -19095,6 +19989,15 @@ export {
|
|
|
19095
19989
|
validateFileStructure,
|
|
19096
19990
|
validateConfig,
|
|
19097
19991
|
validateCommitMessage,
|
|
19992
|
+
PulseDbSourceSchema,
|
|
19993
|
+
PulseSourcesSchema,
|
|
19994
|
+
PulseConfigSchema,
|
|
19995
|
+
validatePulseConfig,
|
|
19996
|
+
BUG_TRACK_CATEGORIES,
|
|
19997
|
+
KNOWLEDGE_TRACK_CATEGORIES,
|
|
19998
|
+
ALL_SOLUTION_CATEGORIES,
|
|
19999
|
+
SolutionDocFrontmatterSchema,
|
|
20000
|
+
validateSolutionsDir,
|
|
19098
20001
|
REQUIRED_SECTIONS,
|
|
19099
20002
|
extractMarkdownLinks,
|
|
19100
20003
|
extractSections,
|
|
@@ -19438,6 +20341,35 @@ export {
|
|
|
19438
20341
|
VERSION,
|
|
19439
20342
|
collectEvents,
|
|
19440
20343
|
send,
|
|
20344
|
+
CompoundLockHeldError,
|
|
20345
|
+
acquireCompoundLock,
|
|
20346
|
+
ALLOWED_FIELD_KEYS,
|
|
20347
|
+
PII_TOKENS,
|
|
20348
|
+
PII_FIELD_DENYLIST,
|
|
20349
|
+
PII_LINE_RE,
|
|
20350
|
+
isSanitizedResult,
|
|
20351
|
+
assertSanitized,
|
|
20352
|
+
writePulseConfig,
|
|
20353
|
+
seedFromStrategy,
|
|
20354
|
+
PulseAdapterAlreadyRegisteredError,
|
|
20355
|
+
registerPulseAdapter,
|
|
20356
|
+
getPulseAdapter,
|
|
20357
|
+
listPulseAdapters,
|
|
20358
|
+
clearPulseAdapters,
|
|
20359
|
+
MOCK_ADAPTER_NAME,
|
|
20360
|
+
registerMockAdapter,
|
|
20361
|
+
parseLookback,
|
|
20362
|
+
computeWindow,
|
|
20363
|
+
runPulse,
|
|
20364
|
+
assembleReport,
|
|
20365
|
+
extractHeadlines,
|
|
20366
|
+
isoWeek,
|
|
20367
|
+
formatIsoWeek,
|
|
20368
|
+
gitScan,
|
|
20369
|
+
computeHotspots,
|
|
20370
|
+
crossReferenceUndocumentedFixes,
|
|
20371
|
+
suggestCategory,
|
|
20372
|
+
assembleCandidateReport,
|
|
19441
20373
|
dist_exports,
|
|
19442
20374
|
init_dist3 as init_dist
|
|
19443
20375
|
};
|